# SocketLearn **Repository Path**: Hxarrxy/socket-learn ## Basic Information - **Project Name**: SocketLearn - **Description**: 学习TCPIP网络编程 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-18 - **Last Updated**: 2024-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## UDP ### UDP回声客户端/服务器端 ### UDP套接字存在数据边界 ![image-20241018153807585](./assets/image-20241018153807585.png) [主机A10.250.19.38](ch06/bound_host1.c)向[主机B10.250.5.103](ch06/bound_host2.c)发送数据的过程如上,主机A的信息几乎在同一时间发送出去,而在接收端收到的信息则是每隔5s收到一次消息。 ```txt Message 1: Hi! Message 2: I'm another UDP host! Message 3: Nice to meet you ``` 这是重要的代码实现,在发送端 ```c sendto(sock, msg1, sizeof(msg1), 0,(struct sockaddr *)&your_adr, sizeof(your_adr)); sendto(sock, msg2, sizeof(msg2), 0,(struct sockaddr *)&your_adr, sizeof(your_adr)); sendto(sock, msg3, sizeof(msg3), 0,(struct sockaddr *)&your_adr, sizeof(your_adr)); ``` 在接收端的实现如下 ```c for (i = 0; i < 3; i++) { sleep(5); adr_sz = sizeof(your_adr); str_len = recvfrom(sock, message, BUF_SIZE, 0, (struct sockaddr *)&your_adr, &adr_sz); printf("Message %d: %s \n", i + 1, message); } ``` 这个现象说明了UDP套接字传输的数据报是有数据边界的,因为发送端发送了3次,接收端收了3次,每个数据报都没有被分割。 在TCP和UDP套接字中,UDP套接字属于未连接套接字,使用`sendto`函数进行数据传输时需要经历三个阶段: 1. **注册目标地址和端口号**:在每次调用`sendto`前,首先需要向UDP套接字注册目标主机的IP地址和端口号。 2. **传输数据**:然后发送数据到已注册的目标。 3. **删除目标地址信息**:最后,清除之前注册的目标地址信息。 由于UDP套接字默认为未连接状态,每次发送数据都需要重复这三个步骤。这在与同一主机进行多次通信时显得不够高效,因为注册和注销地址信息的过程占用了通信时间的近1/3。 因此,将UDP套接字转换为已连接套接字,可以提高效率,尤其是在长时间与同一主机通信时,减少了重复的注册和注销过程,从而提升整体性能。 未连接的UDP套接字 - **定义**:未连接的UDP套接字是指在发送数据时每次都需要指定目标的IP地址和端口号。 - **场景**:适用于需要向多个目标发送数据,或数据发送频繁变化的场合,比如广播、实时视频流等。 已连接的UDP套接字 - **定义**:已连接的UDP套接字是指在创建后,与特定目标地址通过`connect`函数建立了联系。此时,目标地址被固定下来。 - **场景**:适用于长时间与同一目标进行通信的场合,如持续向同一服务器发送数据的应用。 如下,客户端在创建完套接字之后,可以先与服务器建立连接,之后用write写入数据或者read读取数据即可。 ```C // 与服务器地址建立连接,UDP 套接字不需要正式连接,但可以简化发送 connect(sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)); // 向服务器发送数据 // 使用 write 发送数据,自动使用已连接的目标地址 // sendto(sock, message, strlen(message), 0, (struct sockaddr *) &serv_adr, sizeof(serv_adr)); write(sock, message, strlen(message)); // 接收来自服务器的消息 // adr_sz = sizeof(from_adr); // str_len = recvfrom(sock, message,BUF_SIZE,0, (struct sockaddr *)&from_adr,&adr_sz); str_len = read(sock, message, sizeof(message) - 1); // 读取服务器返回的数据 ```