客户端代码
public class MySocket {
public static void main(String[] args) {
try {
InetAddress localHost = InetAddress.getLocalHost();
String hostAddress = localHost.getHostAddress();
System.out.println(hostAddress);
Socket socket = new Socket(hostAddress, 9090);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("1".getBytes("UTF-8"));
outputStream.flush();
outputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端代码
public class MyServerSocket {
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(9090);
System.out.println("等待连接");
Socket socket = server.accept();
System.out.println("连接创建");
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder sb = new StringBuilder();
while ((len = inputStream.read(bytes)) != -1) {
sb.append(new String(bytes, 0, len,"UTF-8"));
}
System.out.println(sb);
inputStream.close();
socket.close();
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这是通过BIO方式实现对端口的监听,弊端是这样只能接收一个tcp链接,那么我们如果想要使服务端能够接收更多的TCP连接,我们需要在主线程中accept更多的TCP连接拿到连接后,通过启动线程的方式来对单条数据进行读写操作
/**
* 多线程方式创建server端为了可以监听多个连接每次拿到连接后开启一个新线程单独处理每个连接不阻塞其他的连接到来
* 无线开辟线程,到达一定数量级存在问题
*/
public class SocketBIOThread {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9090);
System.out.println("Port 9090 has been listening");
for (; ; ) {
// 阻塞获等待客户端连接
Socket client = server.accept();
new Thread(() -> {
try (InputStream in = client.getInputStream()) {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while (true) {
// 阻塞获取数据
String data = reader.readLine();
if (null != data) {
System.out.println(data);
} else {
client.close();
break;
}
}
System.out.println("连接断开");
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
这样可以无限的接收线程,但是弊端是无限开辟线程当TCP连接达到一定数量级之后线程过多,每次对线程的调用会造成用户态内核态的切换,会导致接收数据越来越慢,于是我想到使用线程池来限制连接的个数
/**
* 使用线程池的方式实现BIO,但是连接的数量有限
*/
public class SocketBIOThreadPool {
//server socket listen property:
private static final int RECEIVE_BUFFER = 10;
private static final int SO_TIMEOUT = 0;
private static final boolean REUSE_ADDR = false;
private static final int BACK_LOG = 2;
//client socket listen property on server endpoint:
private static final boolean CLI_KEEPALIVE = false;
private static final boolean CLI_OOB = false;
private static final int CLI_REC_BUF = 20;
private static final boolean CLI_REUSE_ADDR = false;
private static final int CLI_SEND_BUF = 20;
private static final boolean CLI_LINGER = true;
private static final int CLI_LINGER_N = 0;
private static final int CLI_TIMEOUT = 0;
private static final boolean CLI_NO_DELAY = false;
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9090);
System.out.println("Port 9090 has been listening");
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<>(10), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("连接已满");
}
});
while (true){
Socket client = server.accept();
/* client.setKeepAlive(true);
// 设置发送缓冲区大小
client.setSendBufferSize(10);
// 设置不优化tcp在buffer中有数据直接发送不等待缓存区存满
client.setTcpNoDelay(true);*/
threadPool.execute(()->{
try (InputStream in = client.getInputStream()) {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
client.getOutputStream();
while (true) {
// 阻塞获取数据
String data = reader.readLine();
if (null != data) {
System.out.println(data);
} else {
client.close();
break;
}
}
System.out.println("连接断开");
client.close();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
}
这样实现后其实并没有根本的解决问题,这样做只是限制了连接数,但是没有从根本解决问题,所以引出了NIO的方式来建立连接