一、主要用的接口:
//服务器端
-
socket() 创建套接字
-
bind() 绑定套接字
与TCP区别开来,没有listen()、accept()建立连接的过程
-
通信 recvfrom() sendto()
-
close
//客户端
- socket() 创建套接字
与TCP区别开来,没有connect()建立连接的过程
-
通信 sendto() recvfrom()
-
close()
二、代码实例
UDP服务器端:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_socket;
struct sockaddr_in server_addr, client_addr;
char buffer;
socklen_t client_addr_len = sizeof(client_addr);
server_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (server_socket == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
close(server_socket);
exit(EXIT_FAILURE);
}
while (1) {
char message[] = "Hello, client!";
sendto(server_socket, message, strlen(message), 0, (struct sockaddr*)&client_addr, client_addr_len);
sleep(1);
}
close(server_socket);
return 0;
}
UDP客户端:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int client_socket;
struct sockaddr_in server_addr;
char buffer;
socklen_t server_addr_len = sizeof(server_addr);
client_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (client_socket == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &(server_addr.sin_addr));
sendto(client_socket, "Hello, server!", strlen("Hello, server!"), 0, (struct sockaddr*)&server_addr, server_addr_len);
close(client_socket);
return 0;
}
--------------------------------------------------------------------------------------------------------------
附录:
一、接口说明
1. 创建套接字
- 接口 :
int socket(int domain, int type, int protocol);
domain
:地址域,对于IPv4,使用AF_INET
;对于IPv6,使用AF_INET6
。type
:套接字类型,对于UDP,使用SOCK_DGRAM
。protocol
:协议类型,通常设置为0,让系统自动选择UDP协议。
2. 绑定地址(仅服务端)
- 接口 :
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd
:套接字描述符,由socket()
函数返回。addr
:指向sockaddr
结构体的指针,通常使用sockaddr_in
结构体来填充,包含IP地址和端口号。addrlen
:地址结构体的长度。
3. 发送数据
- 接口 :
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
sockfd
:套接字描述符。buf
:指向要发送数据的缓冲区。len
:要发送数据的长度。flags
:发送选项,通常设置为0。dest_addr
:目标地址信息。addrlen
:目标地址信息的长度。
4. 接收数据
- 接口 :
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
sockfd
:套接字描述符。buf
:接收数据的缓冲区。len
:缓冲区的最大长度。flags
:接收选项,通常设置为0。src_addr
:源地址信息(可选)。addrlen
:源地址信息的长度(输入输出型参数)。
5. 关闭套接字
- 接口 :
int close(int sockfd);
sockfd
:套接字描述符。
二、UDP通信说明
UDP(User Datagram Protocol,用户数据报协议)是一种无连接的协议。。
1、UDP通信过程
UDP通信过程主要包括创建套接字(socket)、绑定端口、发送数据和接收数据几个步骤。在Linux环境中,UDP通信通常涉及到socket()
创建套接字、bind()
绑定本地IP地址和端口号、sendto()
发送数据到指定地址、recvfrom()
接收来自指定地址的数据。
2、UDP数据报结构
UDP数据报主要由报头和数据两部分组成,其中报头包括源端口号、目的端口号、长度和校验和四个字段,总共8个字节。UDP报头保证了数据在传输过程中的封装和基本的错误检测。
3、常见问题:UDP丢包问题分析
原因可能包括网络拥堵、防火墙过滤、缓冲区溢出等。可以通过查看系统的接收缓冲区和发送缓冲区的设置,以及相关的统计信息来分析和解决丢包问题。