面向流与面向数据报的服务,你真的理解吗?

    文章来源: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协议,发送端发送的数据,接收端必须一次读完,否则数据将丢失,这就是数据报协议。

    欢迎关注公众号,深入交流~

                                                                     

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值