无连接套接字是一种实现绑定到无连接协议(UDP协议)的套接字,基于无连接套接字的C/S通信模型如下图。
1、UDP服务器端算法的实现流程
(1) UDP服务器端算法的步骤描述
① 调用socket()函数创建服务器端无连接套接字。
② 调用bind()函数将套接字绑定到本机的一个可用的端点地址。
③ 调用recvfrom()函数从套接字接收来自远程客户端的数据并存入到缓冲区中,同时获得远程客户的套接字端点地址并保存。
④ 基于保存的远程客户的套接字端点地址,调用sendto()函数将缓冲区中的数据从套接字发送给该远程客户。
⑤ 与客户交互完毕,调用close()函数将套接字关闭,释放所占用的系统资源。
(2) 代码实现
/*server.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 8000
int main()
{
struct sockaddr_in servaddr, cliaddr;
socklen_t cliaddr_len;
int sockfd;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i, n;
/*打开一个网络通讯端口,分配一个文件描述符sockfd*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));//初始化为空
servaddr.sin_family = AF_INET;//地址采用IPv4地址
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//地址从主机字节顺序转换成网络字节顺序
servaddr.sin_port = htons(SERV_PORT);//端口号从主机字节顺序转换成网络字节顺序
/*将文件描述符sockfd和服务器地址绑定*/
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
printf("等待连接...\n");
while(1){
cliaddr_len = sizeof(cliaddr);
/*接收client端传过来的的字符串,写入buf*/
n = recvfrom(sockfd, buf, MAXLINE, 0, (struct sockaddr*)&cliaddr, &cliaddr_len);
if(n == -1){
printf("recvfrom error");
}
/*打印客户端IP及端口*/
printf("接收到来自地址为 %s 端口号为 %d 的数据\n",
(char*)inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
/*小写转为大写*/
for(i = 0; i<n; i++){
buf[i] = toupper(buf[i]);
}
/*把数据发送给客户端*/
n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
if (n == -1){
printf("sendto error\n");
}
}
return 0;
}
2、UDP客户端算法的实现流程
(1) UDP客户端算法的步骤描述
① 调用socket()函数创建客户端无连接套接字。
② 找到期望与之通信的远程服务器ip地址和协议端口号;然后再调用sendto()函数将缓冲区中的数据从套接字发送给远程服务器。
③ 调用recvfrom()函数从套接字接收来自远程服务器端的数据并存入缓冲区中。
④ 与服务器交互完毕,调用close()函数将套接字关闭,释放所占用的系统资源。
(2) 代码实现
/*client.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
int sockfd, n;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
socklen_t servaddr_len;
/*打开一个网络通讯端口,分配一个文件描述符sockfd*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); //将“点分十进制” -> “二进制整数”
servaddr.sin_port = htons(SERV_PORT);//端口号从主机字节顺序转换成网络字节顺序
while(fgets(buf, MAXLINE, stdin) != NULL){ //输入字符串
/*发送给服务端*/
n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
if(n == -1)
printf("sebdto err\n");
/*从服务端接收数据*/
n = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0);
if(n == -1)
printf("recvfrom err\n");
/*输出服务器处理后的数据*/
write(STDOUT_FILENO, buf, n);
}
close(sockfd);
return 0;
}
运行结果: