recv用TCP和TUDP下的区别

recv是可以用在UDP套接字上的,前提是该套接字调用过bind或者connect,那它用在TCP和UDP套接字上时有什么区别呢?

下面做一个测试,分别使用UDP、TCP实现一对C/S、客户端发送12字节数据,服务器接受的时候用10字节大小的buffer去接受。

TCP

tcpSvr:

 1 /*
 2  * gcc -o tcpSvr ./tcpSvr.c
 3  */
 4 #include <unistd.h>
 5 #include <sys/socket.h>
 6 #include <sys/types.h>
 7 #include <arpa/inet.h>
 8 #include <netinet/in.h>
 9 #include <stdio.h>
10 #include <string.h>
11 #include <errno.h>
12 
13 const int PORT = 8080;
14 
15 int main(int argc, char **argv)
16 {
17     int fd = socket(AF_INET, SOCK_STREAM, 0);
18     if (fd == -1)
19     {
20         perror("socket");
21         return errno;
22     }
23 
24     struct sockaddr_in addr;
25     memset(&addr, 0, sizeof(addr));
26     addr.sin_family = AF_INET;
27     addr.sin_addr.s_addr = INADDR_ANY;
28     addr.sin_port = htons(PORT);
29 
30     if (-1 == bind(fd, (struct sockaddr*)&addr, sizeof(addr)))
31     {
32         perror("bind");
33         return errno;
34     }
35 
36     if (-1 == listen(fd, 5))
37     {
38         perror("listen");
39         return errno;
40     }
41 
42     struct sockaddr_in cli_addr;
43     socklen_t len = sizeof(cli_addr);
44     int client = accept(fd, (struct sockaddr*)&cli_addr, &len);
45     if (client == -1)
46     {
47         perror("accept");
48         return errno;
49     }
50     
51     printf("accept an client\n");
52 
53     char buf[1024];
54     while(1)
55     {
56         memset(buf, 0, 1024);
57         int iRet = recv(client, buf, 10, 0);
58         printf("recv data len [%d]\n", iRet);
59         printf("recv content [%s]\n", buf);
60         sleep(2);
61     }
62     close(fd);
63 
64     return 0;
65 }

tcpCli:

 1 #include <unistd.h>
 2 #include <sys/socket.h>
 3 #include <sys/types.h>
 4 #include <netinet/in.h>
 5 #include <arpa/inet.h>
 6 #include <stdio.h>
 7 #include <string.h>
 8 #include <errno.h>
 9 
10 const int PORT = 8080;
11 
12 int main(int argc, char **argv)
13 {
14     int fd = socket(AF_INET, SOCK_STREAM, 0);
15     if (fd == -1)
16     {
17         perror("socket");
18         return errno;
19     }
20 
21     struct sockaddr_in addr;
22     memset(&addr, 0, sizeof(addr));
23     addr.sin_family = AF_INET;
24     addr.sin_addr.s_addr = inet_addr("127.0.0.1");
25     addr.sin_port = htons(PORT);
26 
27     if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
28     {
29         perror("connect");
30         return errno;
31     }
32 
33     char buf[] = "hello world!";
34     while (1)
35     {
36         int iRet = send(fd, buf, strlen(buf), 0); 
37         printf("Send data len [%d]\n", iRet);
38         printf("Send content [%s]\n", buf);
39         sleep(2);
40     }
41     close(fd);
42 
43     return 0;
44 }

结果:

UDP

udpSvr

 1 #include <unistd.h>
 2 #include <sys/socket.h>
 3 #include <sys/types.h>
 4 #include <arpa/inet.h>
 5 #include <netinet/in.h>
 6 #include <stdio.h>
 7 #include <string.h>
 8 #include <errno.h>
 9 
10 const int PORT = 8080;
11 
12 int main(int argc, char **argv)
13 {
14     int fd = socket(AF_INET, SOCK_DGRAM, 0);
15     if (fd == -1)
16     {
17         perror("socket");
18         return errno;
19     }
20 
21     struct sockaddr_in addr;
22     memset(&addr, 0, sizeof(addr));
23     addr.sin_family = AF_INET;
24     addr.sin_addr.s_addr = INADDR_ANY;
25     addr.sin_port = htons(PORT);
26 
27     if (-1 == bind(fd, (struct sockaddr*)&addr, sizeof(addr)))
28     {
29         perror("bind");
30         return errno;
31     }
32 
33     char buf[1024];
34     while(1)
35     {
36         memset(buf, 0, 1024);
37         int iRet = recv(fd, buf, 10, 0);
38         printf("recv data len [%d]\n", iRet);
39         printf("recv content [%s]\n", buf);
40     }
41     close(fd);
42 
43     return 0;
44 }

udpCli:

 1 #include <unistd.h>
 2 #include <sys/socket.h>
 3 #include <sys/types.h>
 4 #include <netinet/in.h>
 5 #include <arpa/inet.h>
 6 #include <stdio.h>
 7 #include <string.h>
 8 #include <errno.h>
 9 
10 const int PORT = 8080;
11 
12 int main(int argc, char **argv)
13 {
14     int fd = socket(AF_INET, SOCK_DGRAM, 0);
15     if (fd == -1)
16     {
17         perror("socket");
18         return errno;
19     }
20 
21     struct sockaddr_in addr;
22     memset(&addr, 0, sizeof(addr));
23     addr.sin_family = AF_INET;
24     addr.sin_addr.s_addr = inet_addr("127.0.0.1");
25     addr.sin_port = htons(PORT);
26 
27     char buf[] = "hello world!";
28     while (1)
29     {
30         int iRet = sendto(fd, buf, strlen(buf), 0, (struct sockaddr*)&addr, sizeof(addr));
31         printf("Send data len [%d]\n", iRet);
32         printf("Send content [%s]\n", buf);
33         break;
34     }
35     close(fd);
36 
37     return 0;
38 }

结果:

结论:

当收到的数据大于传入recv的buffer大小时,多余的字节,UDP会丢弃,TCP可以在下次调用recv的时候读取到,这也是为什么说TCP是基于流的协议。

所以当读取UDP数据时一定要注意buffer的大小,应使它大于IP层的数据报大小。

还需要注意的是,发送UDP数据的时候包的大小不应该导致IP分片,否则会造成乱序、丢包。

posted @ 2017-01-13 19:02  冷冰若水  阅读(2903)  评论(0编辑  收藏  举报