- 套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:
- 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
- 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
- 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
- Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
- 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
- 连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。
- TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket。
- Socket通信的步骤① 创建ServerSocket和Socket② 打开连接到Socket的输入/输出流③ 按照协议对Socket进行读/写操作④ 关闭输入输出流、关闭Socket
- 服务器端:
- ① 创建ServerSocket对象,绑定监听端口
- ② 通过accept()方法监听客户端请求
- ③ 连接建立后,通过输入流读取客户端发送的请求信息
- ④ 通过输出流向客户端发送信息
- ⑤ 关闭相关资源
- 客户端:
- ① 创建Socket对象,指明需要连接的服务器的地址和端口号
- ② 连接建立后,通过输出流想服务器端发送请求信息
- ③ 通过输入流获取服务器响应的信息
- ④ 关闭响应资源
- 服务器端:
- Socket通信的步骤① 创建ServerSocket和Socket② 打开连接到Socket的输入/输出流③ 按照协议对Socket进行读/写操作④ 关闭输入输出流、关闭Socket
- BIO:
- 服务器端实际有2个socket:一个用于监听,一个用于传输
- 2个堵塞
- 在等待连接accpet时候
- 在等待客户端传输数据read的时候
- 2个堵塞
- 客户端只有一个用于传输
- 这样的通信模式单线程通信无法处理并发(要开线程处理并发,浪费线程资源cpu),因为2次堵塞,当一个客户端和服务器端连接成功之后,如果它不发送任何数据信息,那么服务器端就会一直堵塞等待它发送信息,那么其他的客户端根本无法连接这个服务器。如果有创建的多个线程是不活跃的,只是连接不传递信息,考虑用单线程实现;
- 服务器端实际有2个socket:一个用于监听,一个用于传输
- NIO:
- 如果将read设置为非阻塞:c1进来连接服务器(将其设置为非阻塞),但没法发送信息,从新将服务器设置为等待连接,此时c2连接(也是设置成非阻塞),但此时c1要发送信息了,可能服务器状态在accept那里阻塞了,直接放弃了cpu使用,所以它无法发送信息的,此时就需要将accept也设置成非组赛;
- 此时将accept和read都进行非阻塞设置:SocketChannel和SeverSocketChannel,用ByteBuffer.allocate(BLOCK); 设置缓存空间,再由SocketChannel读取;
- 此处可以将每一个连接的SocketChannel,放进一个list做轮询,有数据就拿出数据读取,但造成了资源浪费,如何让java去主动感知有数据的socket?轮询将给了操作系统的函数
- epoll函数(Unix)当有数据来了,它回直接告诉你是那个socket,不用去做轮询
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 将我们的socket注册给操作系统(在window在就是用select做轮询,在Linux在就是epoll函数)
- redis只有Linux下,只用采用epoll(牛逼)
Socket 编程详解
最新推荐文章于 2023-05-03 17:57:42 发布