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分片,否則會造成亂序、丟包。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM