Skip to content
Browse files

Implement socket API

  • Loading branch information...
1 parent 2800ffe commit 45ee25f68cc191a934be63675d06047969c42fc5 @bigfatbrowncat bigfatbrowncat committed with joshuawarner32
View
90 classpath/java-net.cpp
@@ -9,33 +9,70 @@
details. */
#include "jni.h"
-#include "jni-util.h"
+#include "avian/machine.h"
-#ifdef PLATFORM_WINDOWS
-# include <winsock2.h>
-# define ONLY_ON_WINDOWS(x) x
-#else
-# include <netdb.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# define ONLY_ON_WINDOWS(x)
-#endif
+#include "sockets.h"
+
+using namespace avian::classpath::sockets;
extern "C" JNIEXPORT void JNICALL
-Java_java_net_Socket_init(JNIEnv* ONLY_ON_WINDOWS(e), jclass)
-{
-#ifdef PLATFORM_WINDOWS
- static bool wsaInitialized = false;
- if (not wsaInitialized) {
- WSADATA data;
- int r = WSAStartup(MAKEWORD(2, 2), &data);
- if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) {
- throwNew(e, "java/io/IOException", "WSAStartup failed");
- } else {
- wsaInitialized = true;
- }
- }
-#endif
+Java_java_net_Socket_init(JNIEnv* e, jclass) {
+ init(e);
+}
+
+extern "C" JNIEXPORT SOCKET JNICALL
+Java_java_net_Socket_create(JNIEnv* e, jclass) {
+ return create(e);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_java_net_Socket_connect(JNIEnv* e, jclass, SOCKET sock, long addr, short port) {
+ connect(e, sock, addr, port);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_java_net_Socket_bind(JNIEnv* e, jclass, SOCKET sock, long addr, short port) {
+ bind(e, sock, addr, port);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_java_net_Socket_abort(JNIEnv* e, jclass, SOCKET sock) {
+ abort(e, sock);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_java_net_Socket_close(JNIEnv* e, jclass, SOCKET sock) {
+ close(e, sock);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_java_net_Socket_closeOutput(JNIEnv* e, jclass, SOCKET sock) {
+ close_output(e, sock);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_java_net_Socket_closeInput(JNIEnv* e, jclass, SOCKET sock) {
+ close_input(e, sock);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Avian_java_net_Socket_send(vm::Thread* t, vm::object, uintptr_t* arguments) { /* SOCKET s, object buffer_obj, int start_pos, int count */
+ SOCKET& s = *(reinterpret_cast<SOCKET*>(&arguments[0]));
+ vm::object buffer_obj = reinterpret_cast<vm::object>(arguments[2]);
+ int32_t& start_pos = *(reinterpret_cast<int32_t*>(&arguments[3]));
+ int32_t& count = *(reinterpret_cast<int32_t*>(&arguments[4]));
+ char* buffer = reinterpret_cast<char*>(&vm::byteArrayBody(t, buffer_obj, start_pos));
+ avian::classpath::sockets::send((JNIEnv*)t, s, buffer, count);
+}
+
+extern "C" JNIEXPORT int64_t JNICALL
+Avian_java_net_Socket_recv(vm::Thread* t, vm::object, uintptr_t* arguments) { /* SOCKET s, object buffer_obj, int start_pos, int count */
+ SOCKET& s = *(reinterpret_cast<SOCKET*>(&arguments[0]));
+ vm::object buffer_obj = reinterpret_cast<vm::object>(arguments[2]);
+ int32_t& start_pos = *(reinterpret_cast<int32_t*>(&arguments[3]));
+ int32_t& count = *(reinterpret_cast<int32_t*>(&arguments[4]));
+ char* buffer = reinterpret_cast<char*>(&vm::byteArrayBody(t, buffer_obj, start_pos));
+ return avian::classpath::sockets::recv((JNIEnv*)t, s, buffer, count);
}
extern "C" JNIEXPORT jint JNICALL
@@ -49,7 +86,7 @@ Java_java_net_InetAddress_ipv4AddressForName(JNIEnv* e,
hostent* host = gethostbyname(chars);
e->ReleaseStringUTFChars(name, chars);
if (host) {
- return htonl(reinterpret_cast<in_addr*>(host->h_addr_list[0])->s_addr);
+ return ntohl(reinterpret_cast<in_addr*>(host->h_addr_list[0])->s_addr);
} else {
fprintf(stderr, "trouble %d\n", WSAGetLastError());
}
@@ -67,7 +104,7 @@ Java_java_net_InetAddress_ipv4AddressForName(JNIEnv* e,
if (r != 0) {
address = 0;
} else {
- address = htonl
+ address = ntohl
(reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr.s_addr);
freeaddrinfo(result);
@@ -78,3 +115,4 @@ Java_java_net_InetAddress_ipv4AddressForName(JNIEnv* e,
}
return 0;
}
+
View
15 classpath/java/lang/AutoCloseable.java
@@ -0,0 +1,15 @@
+/* Copyright (c) 2008-2013, Avian Contributors
+
+ Permission to use, copy, modify, and/or distribute this software
+ for any purpose with or without fee is hereby granted, provided
+ that the above copyright notice and this permission notice appear
+ in all copies.
+
+ There is NO WARRANTY for this software. See license.txt for
+ details. */
+
+package java.lang;
+
+public interface AutoCloseable {
+ void close() throws Exception;
+}
View
3 classpath/java/lang/Throwable.java
@@ -123,4 +123,7 @@ public Throwable fillInStackTrace() {
trace = trace(0);
return this;
}
+
+ public void addSuppressed(Throwable exception) {
+ }
}
View
62 classpath/java/net/InetAddress.java
@@ -13,41 +13,61 @@
import java.io.IOException;
public class InetAddress {
- private final String address;
+ private final String name;
+ private final int ip;
- private InetAddress(String address) {
- this.address = address;
+ private InetAddress(String name) throws UnknownHostException {
+ this.name = name;
+ this.ip = ipv4AddressForName(name);
+ if (ip == 0) {
+ throw new UnknownHostException(name);
+ }
}
+ public String getHostName() {
+ return name;
+ }
+
public String getHostAddress() {
- return address;
+ try {
+ return new InetAddress(name).toString();
+ } catch (UnknownHostException e) {
+ return null; // Strange case
+ }
}
- public static InetAddress getByName(String name)
- throws UnknownHostException
- {
+ public static InetAddress getByName(String name) throws UnknownHostException {
try {
Socket.init();
+ return new InetAddress(name);
} catch (IOException e) {
UnknownHostException uhe = new UnknownHostException(name);
uhe.initCause(e);
throw uhe;
}
-
- int address = ipv4AddressForName(name);
- if (address == 0) {
- throw new UnknownHostException(name);
- } else {
- return new InetAddress(ipv4AddressToString(address));
- }
}
- private static String ipv4AddressToString(int address) {
- return (((address >>> 24) ) + "." +
- ((address >>> 16) & 0xFF) + "." +
- ((address >>> 8 ) & 0xFF) + "." +
- ((address ) & 0xFF));
+ public byte[] getAddress() {
+ byte[] res = new byte[4];
+ res[0] = (byte) ( ip >>> 24);
+ res[1] = (byte) ((ip >>> 16) & 0xFF);
+ res[2] = (byte) ((ip >>> 8 ) & 0xFF);
+ res[3] = (byte) ((ip ) & 0xFF);
+ return res;
}
-
- private static native int ipv4AddressForName(String name);
+
+ @Override
+ public String toString() {
+ byte[] addr = getAddress();
+ return (int)((addr[0] + 256) % 256) + "." +
+ (int)((addr[1] + 256) % 256) + "." +
+ (int)((addr[2] + 256) % 256) + "." +
+ (int)((addr[3] + 256) % 256);
+ }
+
+ int getRawAddress() {
+ return ip;
+ }
+
+ static native int ipv4AddressForName(String name);
}
View
17 classpath/java/net/InetSocketAddress.java
@@ -11,16 +11,25 @@
package java.net;
public class InetSocketAddress extends SocketAddress {
- private final String host;
+ private final InetAddress address;
private final int port;
- public InetSocketAddress(String host, int port) {
- this.host = host;
+ public InetSocketAddress(String host, int port) throws UnknownHostException {
+ this.address = InetAddress.getByName(host);
+ this.port = port;
+ }
+
+ public InetSocketAddress(InetAddress address, int port) {
+ this.address = address;
this.port = port;
}
+ public InetAddress getAddress() {
+ return address;
+ }
+
public String getHostName() {
- return host;
+ return address.getHostName();
}
public int getPort() {
View
187 classpath/java/net/Socket.java
@@ -10,10 +10,191 @@
package java.net;
+import java.io.Closeable;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
-public abstract class Socket {
- public static native void init() throws IOException;
+public class Socket implements Closeable, AutoCloseable {
- public abstract void setTcpNoDelay(boolean on) throws SocketException;
+ private static final int SD_RECEIVE = 0x00;
+ private static final int SD_SEND = 0x01;
+ private static final int SD_BOTH = 0x02;
+
+ private static final int BUFFER_SIZE = 65535;
+
+ /**
+ * This method is called from all routines that depend on winsock in windows,
+ * so it has public visibility
+ * @throws IOException
+ */
+ public static native void init() throws IOException;
+
+ /**
+ * Creates the native socket object
+ * @return Handle to the native object
+ * @throws IOException
+ */
+ private static native /* SOCKET */long create() throws IOException;
+
+ /**
+ * Connects the native socket object to an address:port
+ * @param sock Native socket handler
+ * @param addr Address to connect to
+ * @param port Port to connect to
+ * @throws IOException
+ */
+ private static native void connect(/* SOCKET */long sock, long addr, short port) throws IOException;
+ private static native void bind(/* SOCKET */long sock, long addr, short port) throws IOException;
+
+ private static native void send(/* SOCKET */long sock, byte[] buffer, int start_pos, int count) throws IOException;
+ private static native int recv(/* SOCKET */long sock, byte[] buffer, int start_pos, int count) throws IOException;
+
+ private static native void abort(/* SOCKET */long sock);
+ private static native void close(/* SOCKET */long sock);
+ private static native void closeOutput(/* SOCKET */long sock);
+ private static native void closeInput(/* SOCKET */long sock);
+
+ private class SocketInputStream extends InputStream {
+
+ private boolean closed = false;
+
+ @Override
+ public void close() throws IOException {
+ if (!closed) {
+ closeInput(sock);
+ closed = true;
+ }
+ super.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+
+ @Override
+ public int read() throws IOException {
+ byte[] buffer = new byte[1];
+ int size = recv(sock, buffer, 0, 1);
+ if (size == 0) {
+ return -1;
+ }
+ return buffer[0];
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ int fullSize = buffer.length;
+ int index = 0;
+ int size;
+ do {
+ size = recv(sock, buffer, index, Math.min(fullSize, Socket.BUFFER_SIZE));
+ fullSize -= size;
+ index += size;
+ } while (fullSize != 0 && size != 0);
+ return index;
+ }
+
+
+ }
+
+ private class SocketOutputStream extends OutputStream {
+
+ private boolean closed = false;
+
+ @Override
+ public void close() throws IOException {
+ if (!closed) {
+ closeOutput(sock);
+ closed = true;
+ }
+ super.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+
+ @Override
+ public void write(int c) throws IOException {
+ byte[] res = new byte[1];
+ res[0] = (byte)c;
+ send(sock, res, 0, 1);
+ }
+
+ @Override
+ public void write(byte[] buffer) throws IOException {
+ int fullSize = buffer.length;
+ int index = 0;
+ int size;
+ do {
+ size = Math.min(fullSize, Socket.BUFFER_SIZE);
+ send(sock, buffer, index, size);
+ fullSize -= size;
+ index += size;
+ } while (fullSize != 0 && size != 0);
+ }
+
+ }
+
+ private long sock;
+ private SocketInputStream inputStream;
+ private SocketOutputStream outputStream;
+
+ public Socket() throws IOException {
+ Socket.init();
+ sock = create();
+ inputStream = new SocketInputStream();
+ outputStream = new SocketOutputStream();
+ }
+
+ public SocketInputStream getInputStream() {
+ return inputStream;
+ }
+
+ public SocketOutputStream getOutputStream() {
+ return outputStream;
+ }
+
+ public Socket(InetAddress address, int port) throws IOException {
+ this();
+ connect(sock, address.getRawAddress(), (short)port);
+ }
+
+ public Socket(String host, int port) throws UnknownHostException, IOException {
+ this(InetAddress.getByName(host), port);
+ }
+
+ public void bind(SocketAddress bindpoint) throws IOException {
+ if (bindpoint instanceof InetSocketAddress) {
+ InetSocketAddress inetBindpoint = (InetSocketAddress)bindpoint;
+ bind(sock, inetBindpoint.getAddress().getRawAddress(), (short) inetBindpoint.getPort());
+ }
+ }
+
+ public void setTcpNoDelay(boolean on) throws SocketException {}
+
+ @Override
+ public void close() throws IOException {
+ close(sock);
+ }
+
+ public void shutdownInput() throws IOException {
+ inputStream.close();
+ }
+
+ public void shutdownOutput() throws IOException {
+ outputStream.close();
+ }
+
+
+ @Override
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
}
View
12 classpath/java/nio/channels/SocketChannel.java
@@ -50,7 +50,11 @@ public boolean isConnected() {
}
public Socket socket() {
- return new Handle();
+ try {
+ return new Handle();
+ } catch (IOException e) {
+ return null;
+ }
}
public boolean connect(SocketAddress address) throws IOException {
@@ -165,7 +169,11 @@ void handleReadyOps(int ops) {
}
public class Handle extends Socket {
- public void setTcpNoDelay(boolean on) throws SocketException {
+ public Handle() throws IOException {
+ super();
+ }
+
+ public void setTcpNoDelay(boolean on) throws SocketException {
natSetTcpNoDelay(socket, on);
}
}
View
184 classpath/sockets.cpp
@@ -0,0 +1,184 @@
+/* Copyright (c) 2008-2013, Avian Contributors
+
+ Permission to use, copy, modify, and/or distribute this software
+ for any purpose with or without fee is hereby granted, provided
+ that the above copyright notice and this permission notice appear
+ in all copies.
+
+ There is NO WARRANTY for this software. See license.txt for
+ details. */
+
+/*
+ * This file implements a simple cross-platform JNI sockets API
+ * It is used from different classes of the default Avian classpath
+ */
+
+#include "sockets.h"
+
+namespace avian {
+namespace classpath {
+namespace sockets {
+
+int last_socket_error() {
+#ifdef PLATFORM_WINDOWS
+ int error = WSAGetLastError();
+#else
+ int error = errno;
+#endif
+ return error;
+}
+
+
+void init(JNIEnv* ONLY_ON_WINDOWS(e)) {
+#ifdef PLATFORM_WINDOWS
+ static bool wsaInitialized = false;
+ if (not wsaInitialized) {
+ WSADATA data;
+ int r = WSAStartup(MAKEWORD(2, 2), &data);
+ if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) {
+ throwNew(e, "java/io/IOException", "WSAStartup failed");
+ } else {
+ wsaInitialized = true;
+ }
+ }
+#endif
+}
+
+SOCKET create(JNIEnv* e) {
+ SOCKET sock;
+ if (INVALID_SOCKET == (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) {
+ char buf[255];
+ sprintf(buf, "Can't create a socket. System error: %d", last_socket_error());
+ throwNew(e, "java/io/IOException", buf);
+ return 0; // This doesn't matter cause we have risen an exception
+ }
+ return sock;
+}
+
+void connect(JNIEnv* e, SOCKET sock, long addr, short port) {
+ sockaddr_in adr;
+ adr.sin_family = AF_INET;
+#ifdef PLATFORM_WINDOWS
+ adr.sin_addr.S_un.S_addr = htonl(addr);
+#else
+ adr.sin_addr.s_addr = htonl(addr);
+#endif
+ adr.sin_port = htons (port);
+
+ if (SOCKET_ERROR == ::connect(sock, (sockaddr* )&adr, sizeof(adr)))
+ {
+ char buf[255];
+ sprintf(buf, "Can't connect a socket. System error: %d", last_socket_error());
+ throwNew(e, "java/io/IOException", buf);
+ return;
+ }
+}
+
+void bind(JNIEnv* e, SOCKET sock, long addr, short port) {
+ sockaddr_in adr;
+ adr.sin_family = AF_INET;
+#ifdef PLATFORM_WINDOWS
+ adr.sin_addr.S_un.S_addr = htonl(addr);
+#else
+ adr.sin_addr.s_addr = htonl(addr);
+#endif
+ adr.sin_port = htons (port);
+
+ if (SOCKET_ERROR == ::bind(sock, (sockaddr* )&adr, sizeof(adr)))
+ {
+ char buf[255];
+ sprintf(buf, "Can't bind a socket. System error: %d", last_socket_error());
+ throwNew(e, "java/io/IOException", buf);
+ return;
+ }
+}
+
+SOCKET accept(JNIEnv* e, SOCKET sock, long* client_addr, short* client_port) {
+ sockaddr_in adr;
+ SOCKET client_socket = ::accept(sock, (sockaddr* )&adr, NULL);
+ if (INVALID_SOCKET == client_socket) {
+ char buf[255];
+ sprintf(buf, "Can't accept the incoming connection. System error: %d", last_socket_error());
+ throwNew(e, "java/io/IOException", buf);
+ return INVALID_SOCKET;
+ }
+
+ if (client_addr != NULL) {
+ #ifdef PLATFORM_WINDOWS
+ *client_addr = ntohl(adr.sin_addr.S_un.S_addr);
+ #else
+ *client_addr = ntohl(adr.sin_addr.s_addr);
+ #endif
+ }
+
+ if (client_port != NULL) {
+ *client_port = ntohs (adr.sin_port);
+ }
+
+ return client_socket;
+}
+
+void send(JNIEnv* e, SOCKET sock, const char* buff_ptr, int buff_size) {
+ if (SOCKET_ERROR == ::send(sock, buff_ptr, buff_size, 0)) {
+ char buf[255];
+ sprintf(buf, "Can't send data through the socket. System error: %d", last_socket_error());
+ throwNew(e, "java/io/IOException", buf);
+ return;
+ }
+}
+
+int recv(JNIEnv* e, SOCKET sock, char* buff_ptr, int buff_size) {
+ int length = ::recv(sock, buff_ptr, buff_size, 0);
+ if (SOCKET_ERROR == length) {
+ char buf[255];
+ sprintf(buf, "Can't receive data through the socket. System error: %d", last_socket_error());
+ throwNew(e, "java/io/IOException", buf);
+ return 0; // This doesn't matter cause we have risen an exception
+ }
+ return length;
+}
+
+void abort(JNIEnv* e, SOCKET sock) {
+ if (SOCKET_ERROR == ::closesocket(sock)) {
+ char buf[255];
+ sprintf(buf, "Can't close the socket. System error: %d", last_socket_error());
+ throwNew(e, "java/io/IOException", buf);
+ }
+}
+
+void close(JNIEnv* e, SOCKET sock) {
+ if (SOCKET_ERROR == ::shutdown(sock, SD_BOTH)) {
+ int errcode = last_socket_error();
+ if (errcode != ENOTCONN) {
+ char buf[255];
+ sprintf(buf, "Can't shutdown the socket. System error: %d", errcode);
+ throwNew(e, "java/io/IOException", buf);
+ }
+ }
+}
+
+void close_input(JNIEnv* e, SOCKET sock) {
+ if (SOCKET_ERROR == ::shutdown(sock, SD_RECEIVE)) {
+ int errcode = last_socket_error();
+ if (errcode != ENOTCONN) {
+ char buf[255];
+ sprintf(buf, "Can't shutdown the socket. System error: %d", errcode);
+ throwNew(e, "java/io/IOException", buf);
+ }
+ }
+}
+
+void close_output(JNIEnv* e, SOCKET sock) {
+ if (SOCKET_ERROR == ::shutdown(sock, SD_SEND)) {
+ int errcode = last_socket_error();
+ if (errcode != ENOTCONN) {
+ char buf[255];
+ sprintf(buf, "Can't shutdown the socket. System error: %d", errcode);
+ throwNew(e, "java/io/IOException", buf);
+ }
+ }
+}
+
+}
+}
+}
View
72 classpath/sockets.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2008-2013, Avian Contributors
+
+ Permission to use, copy, modify, and/or distribute this software
+ for any purpose with or without fee is hereby granted, provided
+ that the above copyright notice and this permission notice appear
+ in all copies.
+
+ There is NO WARRANTY for this software. See license.txt for
+ details. */
+
+
+/*
+ * This file represents a simple cross-platform JNI sockets API
+ * It is used from different classes of the default Avian classpath
+ */
+
+#ifndef SOCKETS_H_
+#define SOCKETS_H_
+
+#include "avian/common.h"
+#include "jni.h"
+#include "jni-util.h"
+
+#ifdef PLATFORM_WINDOWS
+# include <winsock2.h>
+
+# define ONLY_ON_WINDOWS(x) x
+#else
+# include <netdb.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <unistd.h>
+
+# define ONLY_ON_WINDOWS(x)
+# define SOCKET int
+# define INVALID_SOCKET -1
+# define SOCKET_ERROR -1
+# define closesocket(x) close(x)
+
+# define SD_RECEIVE SHUT_RD
+# define SD_SEND SHUT_WR
+# define SD_BOTH SHUT_RDWR
+
+#endif
+
+namespace avian {
+namespace classpath {
+namespace sockets {
+
+// Library initialization
+void init(JNIEnv* ONLY_ON_WINDOWS(e));
+
+// Socket initialization
+SOCKET create(JNIEnv* e);
+void connect(JNIEnv* e, SOCKET sock, long addr, short port);
+void bind(JNIEnv* e, SOCKET sock, long addr, short port);
+SOCKET accept(JNIEnv* e, SOCKET sock, long* client_addr, short* client_port);
+
+// I/O
+void send(JNIEnv* e, SOCKET sock, const char* buff_ptr, int buff_size);
+int recv(JNIEnv* e, SOCKET sock, char* buff_ptr, int buff_size);
+
+// Socket closing
+void abort(JNIEnv* e, SOCKET sock);
+void close(JNIEnv* e, SOCKET sock);
+void close_input(JNIEnv* e, SOCKET sock);
+void close_output(JNIEnv* e, SOCKET sock);
+
+}
+}
+}
+#endif /* SOCKETS_H_ */
View
37 test/Sockets.java
@@ -0,0 +1,37 @@
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+public class Sockets {
+
+ /**
+ * @param args
+ * @throws IOException
+ * @throws UnknownHostException
+ */
+ public static void main(String[] args) throws UnknownHostException,
+ IOException {
+ System.out.print("Requesting...\n");
+ try (Socket sock = new Socket("www.google.com", 80)) {
+ BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
+ String request = "GET /?gws_rd=cr HTTP/1.1\r\n"
+ + "Host: www.google.com\r\n" + "Accept: */*\r\n"
+ + "User-Agent: Java\r\n" + "Connection: close\r\n" + "\r\n";
+ bw.write(request);
+ bw.flush();
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
+ String read = null;
+ while ((read = br.readLine()) != null) {
+ System.out.println(read);
+ }
+ bw.close();
+ sock.close();
+ }
+ }
+
+}

0 comments on commit 45ee25f

Please sign in to comment.
Something went wrong with that request. Please try again.