在主机之间进行通信的主要传输层协议有两种: TCP和UDP 。在上一篇文章中讨论了创建TCP服务器/客户端。
先决条件:创建TCP服务器/客户端
理论
在UDP中,客户端不像TCP中那样与服务器建立连接,而是仅发送数据报。同样,服务器不需要接受连接,而只是等待数据报到达。到达的数据报包含发送方的地址,服务器用来将数据发送到正确的客户端。
整个过程可以分为以下步骤:
UDP服务器:
- 创建UDP套接字。
- 将套接字绑定到服务器地址。
- 等到数据报包从客户端到达。
- 处理数据报包,并向客户端发送回复。
- 返回步骤3。
UDP客户端:
- 创建UDP套接字。
- 发送消息到服务器。
- 等待直到收到服务器的响应。
- 处理答复,并在必要时返回步骤2。
- 关闭套接字描述符并退出。
必要功能:
int socket(int domain, int type, int protocol)
Creates an unbound socket in the specified domain.
Returns socket file descriptor.
参数:
域–指定通信
域(用于IPv4的AF_INET /用于IPv6的AF_INET6)
type –要创建的套接字类型
(TCP的SOCK_STREAM / UDP的SOCK_DGRAM)
protocol –套接字使用的协议。
0表示对地址系列使用默认协议。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
Assigns address to the unbound socket.
参数:
sockfd –要绑定的套接字的文件描述符
addr –指定要绑定到的地址的结构
addrlen – addr结构的大小
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
Send a message on the socket
参数:
sockfd –套接字的文件描述符
buf –包含要发送的数据的应用程序缓冲区
len – buf应用程序缓冲区的大小
标志–标志的按位或运算以修改套接字行为
dest_addr –包含目标地址的结构
addrlen – dest_addr结构的大小
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
Receive a message from the socket.
参数:
sockfd –套接字的文件描述符
buf –在其中接收数据的应用程序缓冲区
len – buf应用程序缓冲区的大小
标志–标志的按位或运算以修改套接字行为
src_addr –返回包含源地址的结构
addrlen –返回src_addr结构大小的变量
int close(int fd)
Close a file descriptor
参数:
fd –文件描述符
在下面的代码中,显示了服务器和客户端之间的一个hello消息交换,以演示该模型。
UDPServer.c
// Server side implementation of UDP client-server model
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 8080
#define MAXLINE 1024
// Driver code
int main() {
int sockfd;
char buffer[MAXLINE];
char *hello = "Hello from server";
struct sockaddr_in servaddr, cliaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Bind the socket with the server address
if ( bind(sockfd, (const struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len, n;
len = sizeof(cliaddr); //len is value/resuslt
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, ( struct sockaddr *) &cliaddr,
&len);
buffer[n] = '\0';
printf("Client : %s\n", buffer);
sendto(sockfd, (const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &cliaddr,
len);
printf("Hello message sent.\n");
return 0;
}
UDPClient.c
// Client side implementation of UDP client-server model
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 8080
#define MAXLINE 1024
// Driver code
int main() {
int sockfd;
char buffer[MAXLINE];
char *hello = "Hello from client";
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
int n, len;
sendto(sockfd, (const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
printf("Hello message sent.\n");
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, (struct sockaddr *) &servaddr,
&len);
buffer[n] = '\0';
printf("Server : %s\n", buffer);
close(sockfd);
return 0;
}
输出 :
$ ./server
Client : Hello from client
Hello message sent.
$ ./client
Hello message sent.
Server : Hello from server
想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。