单用户UDP服务器的简单实现
今天我们来分享一下单用户UDP服务器的简单实现。
UDP协议是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,所以通过UDP服务器传输的数据不具备可靠性。
其次,说说UDP协议的特点:
1.UDP报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。
2.UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点。
3.但由于UDP传输数据不建立连接,所以UDP几乎不占用过多系统资源。,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
4.UDP传输的吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
5.而且正因为UDP协议的控制选项较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序。
再来说说,UDP服务器和TCP服务器的区别:
1>TCP协议中含了专门的传递保证机制,当数据接收方收到发送方传来的信息时,会自动向发送方发出确认消息;发送方只有在接收到该确认消息之后才继续传送其它信息,否则将一直等待直到收到确认信息为止。
所以,TCP服务器需要利用listen函数来监视,有无服务器来请求链接,并基于请求应答机制,来确保数据的可靠性。
2>而UDP协议并不提供数据传送的保证机制。如果在从发送方到接收方的传递过程中出现数据报的丢失,协议本身并不能做出任何检测或提示。
因此,UDP服务器不需要监视有无服务器来请求链接,也没有请求应答机制,来确保数据的可靠性。所以通过UDP服务器传输的数据不具备可靠性。
UDP在用户空间实现可靠性:
由于UDP服务器传输的数据不具备可靠性,所以它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向事务的简单不可靠信息传送服务。虽然UDP是一个不可靠的协议,但它是分发信息的一个理想协议。
UDP可以采用重发请求(ARQ)协议来要实现无差错的传输数据,能一定程度上,实现在用户空间的可靠性。而重发请求(ARQ)协议又可分为连续ARQ协议、选择重发ARQ协议、滑动窗口协议。
采用滑动窗口协议,限制已发送出去但未被确认的数据帧的数目。循环重复使用已收到的那些数据帧的序号。具体实现是在发送端和接收端分别设定发送窗口和接收窗口。
于是,在接收窗口和发送窗口间存在着这样的关系:接收窗口发生旋转后,发送窗口才可能向前旋转,接收窗口保持不动时,发送窗口是不会旋转的。这种收发窗口按如此规律顺时钟方向不断旋转的协议就犯法为滑动窗口协议。
最后来说说实现的单用户的UDP服务器的步骤和源代码以及实现后的运行示例。
服务器端
1>Main函数传参 argc argv[],包含服务器的端口号8080和IP地址
2>用socket函数创建listen_socket套接字
3>用bind函数绑定套接字和端口号以及IP
循环体:
4>利用UDP服务器特有的recvfrom()函数来读取数据。
5>利用UDP服务器特有的sendto()函数来发送数据。
客服端
1>Main函数传参 argc argv[],包含服务器的端口号8080和IP地址
2>用socket函数创建套接字
3>利用UDP服务器特有的sendto()函数来发送数据。
4>利用UDP服务器特有的recvfrom()函数来读取数据。
源代码如下:
server.c
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h>
5 #include<string.h>
6
7 static void usage(char* proc){
8 printf("usage %s:[local_ip],[local_port]\n", proc);
9 }
10
11 int main(int arg, char* argv[]){
12 if(arg != 3){
13 usage(argv[0]);
14 return 1;
15 }
16
17 int sock = socket(AF_INET, SOCK_DGRAM, 0);
18 if(sock<0){
19 perror("socket");
20 return 2;
21 }
22
23 struct sockaddr_in server
24 server.sin_family = AF_INET;
25 server.sin_port = htons(atoi(argv[2]));
26 server.sin_addr.s_addr = inet_addr(argv[1]);
27 if(bind(sock,(struct sockaddr*)&server,sizeof(server))<0){
28 perror("bind");
29 return 3;
30 }
31
32 char buf[1024];
33 while(1){
34 struct sockaddr_in client;
35 socklen_t len = sizeof(client);
36 ssize_t s = recvfrom(sock, &buf, sizeof(buf)-1, \
37 0,(struct sockaddr*)&client, &len);
38 if(s>0)
39 {
40 buf[s]=0;
41 printf("client[%s,%d] say#%s\n",\
42 inet_ntoa(client.sin_addr),\
43 ntohs(client.sin_port), buf);
44 char* msg="can you see me!";
45 ssize_t x = sendto(sock, msg, strlen(msg), 0,\
46 (struct sockaddr*)&client, len);
47 }
48 }
49
50 close(sock);
51 return 0;
52
53 }
client.c
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h>
5 #include<string.h>
6
7 static void usage(char* proc){
8 printf("usage %s:[server_ip],[server_port]\n", proc);
9 }
10
11 int main(int arg, char* argv[]){
12 if(arg != 3){
13 usage(argv[0]);
14 return 1;
15 }
16
17 int sock = socket(AF_INET, SOCK_DGRAM, 0);
18 if(sock<0){
19 perror("socket");
20 return 2;
21 }
22
23 struct sockaddr_in server;
24 server.sin_family = AF_INET;
25 server.sin_port = htons(atoi(argv[2]));
26 server.sin_addr.s_addr = inet_addr(argv[1]);
27 socklen_t len = sizeof(server);
28
29 char buf[1024];
30 while(1){
31 printf("please enter#");
32 fflush(stdout);
33 ssize_t s = read(0,buf,sizeof(buf)-1);
34 if(s>0){
35 buf[s-1]=0;
36 sendto(sock, &buf, strlen(buf), 0\
37 ,(struct sockaddr*)&server, sizeof(server));
38 ssize_t s = recvfrom(sock, buf, sizeof(buf)-1, \
39 0,(struct sockaddr*)&server, &len);
40 if(s>0)
41 {
42 buf[s]=0;
43 printf("server[%s,%d] say#%s\n",\
44 inet_ntoa(server.sin_addr),\
45 ntohs(server.sin_port), buf);
46 }
47 }
48 }
49
50 close(sock);
51 return 0;
52
53 }
Makefile
1 .PHONY:all
2 all:rclient rserves
3
4 rclient:client.c
5 gcc -o $@ $^
6 rserves:serves.c
7 gcc -o $@ $^
8
9 .PHONY:clean
10 clean:
11 rm -f rclient rserves
运行结果
多用户的UDP服务器的实现和多用户TCP服务器的实现相差无几,就不实现了,有需求请评论,可私发。
此次分享如上!如有错误,望指正!愿共同进步!