南宁建站网站模板,广告联盟接广告,响应式网站模板费用,个人网站建设规划案例文章目录 引言正文基于TCP协议的Socket通信基于UDP协议的Socket通信服务端如何接收更多项目多进程多线程IO多路复用select轮询IO多路复用epoll事件通知 使用Socket实现同一个机器上的多线程通信服务端创建对应socket监听端口客户端发起对应的连接请求 总结 引言
上次面试腾讯的… 文章目录 引言正文基于TCP协议的Socket通信基于UDP协议的Socket通信服务端如何接收更多项目多进程多线程IO多路复用select轮询IO多路复用epoll事件通知 使用Socket实现同一个机器上的多线程通信服务端创建对应socket监听端口客户端发起对应的连接请求 总结 引言
上次面试腾讯的时候反复提到了socket通信不仅仅是不同机器不同进程之间的通信同一个机器上不同进程之间的通信也是用这个用的比较广泛这里是我的知识盲区了感觉面经上看到过好几次了这里还是总结一下补充一下信息来源
正文
Socket通信是进行端到端的通信对于下层经过多少局域网、路由器是透明的。进行Socket通信需要指定两个地方分别是使用IP层协议和传输层协议 IP层协议 IPv4AF_INETIPv6AF_INET6 传输层协议 TCP》》基于字节流》》SOCK_STREAMUDP》》基于数据报》》SOCK_DGRAM
基于TCP协议的Socket通信 在服务端进行Socket通信时会维护两个Socket一个是监听的Socket还有一个是专门用来通信的已连接的Socket通信 监听Socket 服务器用来监听客户端链接请求的Socket会一直等待连接请求常规的监听8080端口 已连接Socket 当某一个客户端连接到服务器后服务器会为客户端A生成一个新的Socket 此后客户端A和服务器之间的消息传输都是通过这个已有连接的Socket进行监听Socket继续等待其他客户端的连接请求
1、服务端设置监听Socket步骤
bind 绑定IP地址和端口 listen 服务端进入监听状态客户端可以进行发起连接当前的监听Socket会陷入阻塞维系两个队列 established状态的全连接队列syn_rcvd状态的半链接队列 accept 返回一个新的已经建立的Socket进行数据传输
2、服务器端创建通信Socket过程
accept 创建一个新的socket这个socket是表示服务器和某一个特定客户端的连接当前链接的标识[客户端IP客户端端口监听Socket的IP监听Socket的端口] send和revc 通过这三个数据进行手法数据
3、客户端发起连接创建Socket的过程
connect 通过connect发起连接指定目标IP地址和端口号内核临时为客户端分配一个端口进行三次握手 Socket的发送接收的底层实现 在Linux中是以文件的形式存在的有对应的文件描述符写入和读出都是通过文件描述符 每一个Socket中都有两个队列分别是发送队列和接受队列每一个队列保存完整的数据包 进程和文件的关系 每一个进程都有自己的task_struct指向能够操作的文件描述符数组每一个元素是指向内核中打开的文件的列表进程通过操作对应文件结构进行调用Socket进行发送数据和接受数据 基于UDP协议的Socket通信
UDP通信比起TCP通信有以下几个差异 没有链接 不需要三次握手不需要在额外创建一个socket通信 不用调用listen和connect 直接bind即可开启监听端口等 只需要使用sendto和recvfrom进行接收即可 服务端如何接收更多项目
最大连接数计算 标识连接的唯一标志——四元组{本机IP本机端口目标IP目标端口}2的32次方2的16次方最大连接数是2的48次方受限因素 文件描述符限制系统中ulimit限制内存限制每一个TCP链接都要占用内存内存有限
多进程 实现 每次接收到一个新的socket就会创建一个新的子进程解决 具体实现 父进程调用Fork创建子进程执行如下操作 复制一个文件描述符列表复制内存空间指令计数器当前程序运行的位置 父进程因为刚才accept创建的已经链接的Socket也是一个文件描述符同样会被子进程获得子进程完成任务通信完毕之后退出返回0标识自己是子进程
多线程 实现 每次创建一个新的连接创建一个新的socket就创建一个新的线程解决 具体实现 主线程调用的pthread_create创建一个新的线程 新线程共享进程的资源 新线程通过通过已经连接的Socket请求完成通信
没有办法解决C10K问题
IO多路复用select轮询 实现 一个线程负责所有的Socket依次查看每一个Socket进行读写操作 具体实现 Socket本身是文件描述符保存在一个文件描述符集合中fd_set中调用select函数轮询所有的文件描述符是否有变化将发生变化的文件描述符状态位设置为1
IO多路复用epoll事件通知
同样都是多路复用只不过这里的调用函数不一样是使用epoll的方式这里仅仅总结一下对应的差异就行了 注册通知替换轮询 epoll_create创建监听的epoll对象通过callback函数的方式当某一个文件描述符发生变化的时候主动通知 红黑树保存socket epoll_ctl实现节点加入红黑树将需要监听的节点加入到红黑树中快速定位发生时间的节点然后进行监听。
使用Socket实现同一个机器上的多线程通信
服务端创建对应socket监听端口
使用java.net.Socket进行编程 创建对应的监听Socket调用对应的accpet函数获取连接每一个连接socket都交给一个新的线程处理
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class Main {private static final int PORT 12345;public static void main(String[] args) {try (ServerSocket serverSocket new ServerSocket(PORT)) {System.out.println(Server started on port PORT);while (true) {Socket clientSocket serverSocket.accept();System.out.println(New client connected: clientSocket.getInetAddress().getHostAddress());// 每个连接交给一个新的线程处理new Thread(new ClientHandler(clientSocket)).start();}} catch (IOException e) {e.printStackTrace();}}
}处理通信的线程
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;public class ClientHandler implements Runnable {private Socket clientSocket;public ClientHandler(Socket socket) {this.clientSocket socket;}Overridepublic void run() {try (BufferedReader in new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));PrintWriter out new PrintWriter(clientSocket.getOutputStream(), true);) {String message;while ((message in.readLine()) ! null) {System.out.println(Received from client: message);out.println(Echo: message);if (message.equalsIgnoreCase(exit)) {break;}}} catch (IOException e) {e.printStackTrace();} finally {try {clientSocket.close();} catch (IOException e) {e.printStackTrace();}}}
}客户端发起对应的连接请求
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;public class Main {private static final String SERVER_ADDRESS localhost;private static final int SERVER_PORT 12345;public static void main(String[] args) {try (Socket socket new Socket(SERVER_ADDRESS, SERVER_PORT);PrintWriter out new PrintWriter(socket.getOutputStream(), true);BufferedReader in new BufferedReader(new InputStreamReader(socket.getInputStream()));BufferedReader stdIn new BufferedReader(new InputStreamReader(System.in))) {String userInput;while ((userInput stdIn.readLine()) ! null) {out.println(userInput);System.out.println(Server response: in.readLine());if (userInput.equalsIgnoreCase(exit)) {break;}}} catch (IOException e) {e.printStackTrace();}}
}总结
今天大概了解了Socket通信的相关内容下次再遇到类型的题目大差不差都有一点印象在考到再拿过来复习就行了主要有以下几个部分 Socket通信在TCP连接中的应用Socket通信在UDP连接中的应用如何解决多个Socket通信的问题本地如何使用Socket通信进行通信