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”。

原文地址:https://www.cnblogs.com/embedded-linux/p/4998811.html