socket是应用层与TCP/IP协议族通信的中间软件抽象,操作系统把传输层一下的内容都包装了,应用层只需要用socket即可完成网络请求
Tcp是基于流;UDP是基于DatagramPacket数据报;socket可以利用DatagramPacket进行UDP通信
private static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2);
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(10001));
System.out.println("start server ....");
try {
while (true){
executorService.execute(new ServerTask(serverSocket.accept()));
}
}finally {
serverSocket.close();
}
}
private static class ServerTask implements Runnable{
private Socket socket;
public ServerTask(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//这样会自动关闭流
try (ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());) {
String input = inputStream.readUTF();
System.out.println("accept input :" +input);
outputStream.writeUTF("hello " + input);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws IOException {
Socket socket = new Socket();
InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 10001);
ObjectOutputStream outputStream = null;
ObjectInputStream inputStream = null;
try {
socket.connect(inetSocketAddress);
outputStream = new ObjectOutputStream(socket.getOutputStream());
inputStream = new ObjectInputStream(socket.getInputStream());
outputStream.writeUTF("hello");
outputStream.flush();
System.out.println(inputStream.readUTF());
} finally {
if (socket != null) {
socket.close();
}
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
}
}
Selector、ServerSocketChannel、SocketChannel、Buffer、应用程序
服务端一个线程里面,会有一个Selector,用于接收客户端发来的事件,比如连接、有数产生事件等
ServerSocketChannel:用于处理连接事件,会在Selector里注册OP_ACCEPT事件监听,Selector收到客户端连接事件后会通知ServerSocketChannel;
SocketChannel:用于处理数据读的事件,一个客户端会对应一个SocketChannel;同样它会注册数据读的事件到Selector,有数据发送来了以后,Selector就会通知对应的SocketChannel;
Buffer:用于SocketChannel与服务端应用程序直接的数据操作,有数据时,SocketChannel会写到缓冲区Buffer中,然后应用程序从Buffer中读数据,处理完又写回到Buffer,然后SocketChannel从Buffer中读
有新的客户端连接进来后,会创建新的SocketChannel,进行数据的读写通信
堆上分配:分配速度会快一点,网络通信慢一点,一般业务处理方面多一点
ByteBuffer buffer = ByteBuffer.allocate(20000);
直接内存分配:分配速度会慢一点,网络通信会快一点,一般直接读写网络数据用这个
ByteBuffer buffer = ByteBuffer.allocateDirect(20000);
把byte数组转换为Buffer
ByteBuffer.wrap(bytes)
我们一般很少使用OP_WRITE事件,因为操作系统在建立socket连接的时候,会为socket创建2个缓冲区(Buffer),一个发送Buffer,一个接收Buffer;当客户端向服务端发送数据的时候,服务端接收缓存接收到数据,就会触发OP_READ事件;这2个缓冲区由操作系统内核管理。
而发送缓存里面只要还有空间可写,哪怕一个字节,就会触发OP_WRITE事件
websocket实现,websocket本身定义了跟心跳有关的2个数据帧,实现以后,服务端会自动解析和应答
想深入网络学习的可以参考读一读,都是经典。
作者介绍
中年程序猿,十年移动端开发老司机,分享一线开发经验和知识,正在探索通过副业渡过中年危机
越努力越幸运,加油💪,一起遇见更好的自己