• TCP&UDP


    TCP协议是面向流的协议,在底层通信中这些数据可以被拆成许多数据包发送,但是一个数据包有多少字节对应用程序是不可见的。

    TCP接收到的数据需要做分包处理(无法区分每一包数据)。

    注:TCP客户端发送的数据拆包处理,则TCP服务器端只有完整接收到数据包后才会通过read上报上层可以read数据了。

    比如发送端发送了一包数据,被查分成3包:序号1,序号2,序号3。由于某种原因,3个包未全部收到时,上层read不会返回(阻塞)或无事件(socket不可读,非阻塞)。只有3个包都收到后,Socket才可read。若包未收取成功,会要求对端重发。长时间未收到包,怎样处理????若阻塞,则一直等待;若非阻塞,则不会触发读时间。当判断对端断开后,read()返回0。

    //tcp server
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/un.h>
    #include <sys/socket.h>
    #include <sys/stat.h>
    #include <errno.h>
    
    #define BUF_SIZE 10
    
    #define DES_PATH "/tmp/main.socket"
    
    int main(int argc, char *argv[])
    {
        int sd, cfd;
        struct sockaddr_un un, peer_un;
        socklen_t len;
        int i;
        int ret;
        char buf[BUF_SIZE];
    
        sd = socket(AF_UNIX, SOCK_STREAM, 0); 
        if(sd < 0)
        {
            perror("socket");
            return -1;
        }
    
        unlink(DES_PATH);
        memset(&un, 0, sizeof(struct sockaddr_un));
        un.sun_family = AF_UNIX;
        strncpy(un.sun_path, DES_PATH, sizeof(un.sun_path) - 1);
        ret = bind(sd, (struct sockaddr *)&un, sizeof(struct sockaddr_un));
        if(ret < 0)
        {
            perror("bind");
            return -1;
        }
    
        ret = listen(sd, 100);
    
        while(1)
        {
            len = sizeof(struct sockaddr_un);
            cfd = accept(sd, (struct sockaddr *)&peer_un, &len);
            if(cfd < 0)
            {
                perror("accept");
                return -1;
            }
            while(1)
            {
                memset(buf, 0, BUF_SIZE);
                sleep(10);
                ret = read(cfd, buf, BUF_SIZE);
    
                if(ret > 0)
                {
                    printf("Recvfrom [%d] bytes from >>%s:
    ", ret, peer_un.sun_path);
                    for(i = 0; i < BUF_SIZE; i++)
                    {
                        printf("0x%.2x	", 0xFF&buf[i]);
                        if(0 == (i + 1) % 5)
                        {
                            printf("
    ");
                        }
                    }
                } else if(ret == 0){
                    printf("peer close
    ");
                    close(cfd);
                    break;
                } else {
                    if(errno == EINTR)
                    {
                        break;
                    } else {
                        perror("read");
                        return -1;
                    }
                }
            }
        }
    
        close(sd);
    
        return 0;
    }
    // tcp client
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <stddef.h>
    #include <fcntl.h>
    #include <time.h>
    #include <sys/un.h>
    #include <sys/socket.h>
    #include <sys/stat.h>
    
    int main(int argc, char *argv[])
    {
        int sd; 
        struct sockaddr_un un; 
        socklen_t len;
        int tnode;
        int ret ;
    
        if(argc < 2)
        {   
            return -1; 
        }   
        tnode = atoi(argv[1]);  
        sd = socket(AF_UNIX, SOCK_STREAM, 0);
        if(sd < 0)
        {
            perror("socket");
            return -1;
        }
    
        memset(&un, 0, sizeof(struct sockaddr_un));
        un.sun_family = AF_UNIX;
    //  strcpy(un.sun_path, "/tmp/main.socket");
        snprintf(un.sun_path, sizeof(struct sockaddr_un), "%u.%u.sock", time(NULL), getpid());
    
        printf("sockaddr is %s
    ", un.sun_path);
        ret = bind(sd, (struct sockaddr *)&un, sizeof(struct sockaddr_un));
        if(ret < 0)
        {
            perror("bind");
            return -1;
        }
    
        memset(&un, 0, sizeof(struct sockaddr_un));
        un.sun_family = AF_UNIX;
        strcpy(un.sun_path, "/tmp/main.socket");
    
        len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path) + 1;
    
        ret = connect(sd, (struct sockaddr *)&un, len);
        if(ret < 0)
        {
            perror("connect");
            return -1;
        } else {
            write(sd, &tnode, sizeof(int));
            write(sd, &tnode, sizeof(int));
            write(sd, &tnode, sizeof(int));
        }
    
        close(sd);
    
        return 0;
    }
    ~$./tc 1000
    sockaddr is 1480431031.3755.sock
    ~$./tc 100
    sockaddr is 1480431034.3756.sock
    ~$./ts
    Recvfrom [10] bytes from >>1480431031.3755.sock:
    0xe8    0x03    0x00    0x00    0xe8    
    0x03    0x00    0x00    0xe8    0x03    
    Recvfrom [2] bytes from >>1480431031.3755.sock:
    0x00    0x00    0x00    0x00    0x00    
    0x00    0x00    0x00    0x00    0x00    
    peer close
    Recvfrom [10] bytes from >>1480431034.3756.sock:
    0x64    0x00    0x00    0x00    0x64    
    0x00    0x00    0x00    0x64    0x00    
    Recvfrom [2] bytes from >>1480431034.3756.sock:
    0x00    0x00    0x00    0x00    0x00    
    0x00    0x00    0x00    0x00    0x00    
    peer close

    在server端读数据前延迟一段时间如10s,在client端一个sock多次write相同数据,server读取数据为当前缓冲区中所有数据(多个包已合并),可知TCP需做分包处理。

    UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据。

    UDP每读取一次都是一包数据(UDP已做分包处理),无需再做分包处理。

    具体事例可参考“Unix domain socket IPC”。

  • 相关阅读:
    Idea 代码编辑错误不飘红提示
    Java序列化机制和原理
    tomcat 启动报错org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalin
    idea tomcat 怎样出现update classes and resources
    Java List序列化的实现
    Spring管理的bean初始化方法的三种方式,以及@PostConstruct不起作用的原因
    Tomcat 启动或者发布项目时提示Publishing failed:Resource /xxxx does not exist
    spring中的context:include-filter和context:exclude-filter的区别
    oracle字符集修改
    VML、SVG、Canvas简介
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/4998811.html
Copyright © 2020-2023  润新知