文章来源:https://blog.csdn.net/zhangjiehuan/article/details/93367731
相信大家都听说过TCP是面向流的服务,UDP是面向数据报的服务,那面向流与面向数据报,是什么意思呢?教科书上一般会解释说,面向流是指无边界,面向数据报是有边界的,这个解释似乎还是难以理解。今天小编从编码的角度来给大家分析下这两个概念。
先做实验,首先是UDP协议。客户端向服务端发送1024字节数据,服务端先接收100字节,然后再接收100字节。
实 验
UDP实验
服务端代码:
//udp_server.c
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
int sockfd;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t addrlen =sizeof(client);
char buf[1024] = {0};
int n = -1;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Creatingsocket failed.");
exit(1);
}
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_addr.s_addr= htonl(INADDR_ANY);
server.sin_port=htons(54321);
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1) {
perror("Bind()error.");
exit(1);
}
//客户端会一次发送1024字节数据
//第一次我们只接收100字节
n = recvfrom(sockfd,buf,100,0,(struct sockaddr*)&client,&addrlen);
if (n < 0) {
perror("recvfrom() error\n");
exit(1);
}
printf("first recv %d bytes\n",n);
//然后再接收100字节
n = recvfrom(sockfd,buf,100,0,(struct sockaddr*)&client,&addrlen);
if (n < 0) {
perror("recvfrom() error\n");
exit(1);
}
printf("second recv %d bytes\n",n);
close(sockfd);
}
客户端代码:
//udp_client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int main(int argc, char *argv[])
{
int sockfd = -1, n = -1;
char buf[1024] = {0};
struct hostent *he;
struct sockaddr_in server,peer;
if ((sockfd=socket(AF_INET, SOCK_DGRAM,0))==-1) {
printf("socket() error\n");
exit(1);
}
bzero(&server,sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_port = htons(54321);
//向服务端发送1024字节数据
n = sendto(sockfd, buf,1024,0,(struct sockaddr *)&server,sizeof(server));
if(n > 0)
printf("send %d bytes\n",n);
while(1);
close(sockfd);
}
实验结果:
[root@promote ~]# gcc udp_server.c -o server
[root@promote ~]# ./server
first recv 100 bytes
[root@promote ~]# gcc udp_client.c -o client
[root@promote ~]# ./client
send 1024 bytes
实验结果显示,服务端只接收到100字节数据,第二次读取时,阻塞了。先不解释原因,同样的实验,我们看看TCP协议会是什么情况?
TCP实验
服务端代码:
//tcp_server.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int serverfd = socket(AF_INET,SOCK_STREAM,0);
assert(serverfd > 0);
struct sockaddr_in address;
bzero(&address,sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(54321);
int ret = bind(serverfd, (struct sockaddr* )&address,sizeof(address));
assert(ret != -1);
ret = listen(serverfd, 5);
assert(ret != -1);
struct sockaddr_in client_addr;
socklen_t len = sizeof(len);
int clientfd = accept(serverfd, (struct sockaddr* )&client_addr, &len);
assert(clientfd != -1);
char buf[1024] = {0};
//客户端共发送1024字节
//第一次接收100字节
int n = recv(clientfd,buf,100,0);
assert(n != -1);
printf("first recv %d bytes\n",n);
//第二次接收100字节
n = recv(clientfd,buf,100,0);
assert(n != -1);
printf("first recv %d bytes\n",n);
while(1);
close(clientfd);
close(serverfd);
return 0;
}
客户端代码:
//tcp_client.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = socket(AF_INET,SOCK_STREAM,0);
assert(fd > 0);
struct sockaddr_in address;
bzero(&address,sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(54321);
int ret = connect(fd, (struct sockaddr* )&address, sizeof(address));
assert(ret != -1);
char sendbuf[1024] = {0};
ret = send(fd, sendbuf,1024,0);//发送1024字节数据
assert(ret != -1);
printf("send %d bytes\n",ret);
while(1);
close(fd);
return 0;
}
实验结果:
[root@promote ~]# gcc tcp_server.c -o server
[root@promote ~]# ./server
first recv 100 bytes
first recv 100 bytes
[root@promote ~]# gcc tcp_client.c -o client
[root@promote ~]# ./client
send 1024 bytes
1[root@promote ~]# gcc tcp_client.c -o client
2[root@promote ~]# ./client
3send 1024 bytes
实验表明,服务端第一次接收100字节,第二次也接收了100字节。
比较两个实验,发现对于UDP协议,客户端发送1024字节,服务端第一次读取100字节,然后再读时,读不到数据了,而对于TCP协议,服务端第一次读取100字节,第二次仍旧可以再读到数据。
结论
对于TCP协议,发送端发送数据的次数与接收端接收数据的次数没有关系,这就是字节流的概念。而对于UDP协议,发送端发送的数据,接收端必须一次读完,否则数据将丢失,这就是数据报协议。
欢迎关注公众号,深入交流~