Linux C/C++之TCP / UDP通信

简介: 这篇文章详细介绍了Linux下C/C++语言实现TCP和UDP通信的方法,包括网络基础、通信模型、编程示例以及TCP和UDP的优缺点比较。

1. 什么是网络

1.1 网络的定义

网络(Network)是由若干节点和连接这些节点的链路构成的图,表示诸多对象及其相互联系。网络有资源共享、快速传输信息、提高系统可靠性、易于进行分布式处理和综合信息服务等特性。

1.2 网络的实质

网络就是多个主机连接到一起, 各个主机之间可以传输信息, 资源共享等功能。

1.3 主机的类型

主机可以是交换机,基站,路由器,电脑,手机等等

1.4 信息的传递

基站与基站之间通过无线电进行信息的传递。或者其它主机之间通过光,电等物理媒介进行信息的传递。

2. 网络分层

2.1 五层模型

  1. 应用层
  2. 传输层
  3. 网络层
  4. 数据链路层
  5. 物理层

2.2 七层模型(OSI Open System Interconnection)

  1. 应用层
  2. 表示层
  3. 会话层
  4. 传输层
  5. 网络层
  6. 数据链路层
  7. 物理层

2.3 每层作用以及相关协议

应用层:为操作系统或网络应用程序提供访问网络服务的接口,常见的协议有 FTP HTTP HTTPS SMTP DNS等。

表示层:提供数据格式转换服务,解密与加密,图片的解码与编码,数据的压缩和解压缩,常见协议有 URL加密 口令加密 图片编解码等等。

会话层:建立端连接并提供访问验证和会话管理,例如使用效验点可使会话在通信失效时从效验点恢复通信。常见:服务器验证用户登录,断点续传。

传输层:提供应用进程之间的逻辑通信,建立连接,处理数据包错误,处理数据包次序,常见协议:TCP UDP SPX

网络层:为数据在结点之间传输创建逻辑链路,并分组转发数据。例如,对子网间的数据包进行路由选择,常见的有路由器,多层交换机,防火墙,IP,IPX,RIP,OSPF。

数据链路层:在通信实体建立数据链路连接。例如,将数据分帧并处理流控制,物理地址寻址,重发等。常见的有网卡,网桥,二层交换机。

物理层:为数据端设备提供原始比特流的传输通路。例如,网络通信的数据传输介质由电缆与设备共同构成。常见的有中继器,集线器,网线,HUB等。

3. ip, 网关,子网掩码,端口

3.1 ip(Internet Protocol)

网络之间互连的协议,也就是为计算机网络相互连接进行通信而设计的协议,IP协议也可以叫做因特网协议。**ip用来区分网络中的不同主机,例如ipv4的本质就是一个4字节(byte)的无符号(unsigned)整数。**

例如: 192.168.1.123 数点格式字符串

3.2 网关

网关(Gateway)又称网间连接器、协议转换器。网关在网络层以上实现网络互连,是复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。 网关是一种充当转换重任的计算机系统或设备。使用在不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。

3.3 子网掩码

子网掩码前三段确定路由,最后一段确定主机,子网掩码为(255.255.255.0),使用子网掩码&ip地址可以得到IP地址的前三段,使用(~子网掩码)&ip可以得到IP地址的最后一段。

3.4 端口

在同一个主机之上有多个端口,每个进程使用唯一的一个端口,例如浏览器使用 80 号端口,一般端口都是从小到大使用的,个人写的应用程序一般建议使用5000以上的端口号,一般计算机有 0 --- 65535 共计 65536 个端口,因此建议使用10000左右的端口比较稳妥。

4. 大小端系统

4.1 大端系统

低位数据存放在高地址,高位数据存放在低地址。

4.2 小端系统

低位数据存放在低地址,高位数据存放在高地址。

4.3 注意事项

网络服务器均为大端系统(因为网络服务器一般是UNIX系统),因此在编写网络通信的代码时需要将小端转换为大端

大小端存储模型

小端系统的存储

#include <stdio.h>

union uu{
    char c[4];
    int n;
};
int main(){
    //类型  决定  存储方式 和 占用空间大小
    //int 4字节     x86架构    arm架构   ......
    //0x11223344   小端系统    大端系统

    union uu u;
    u.n = 0x11223344;
    printf("%x %x %x %x\n",u.c[0],u.c[1],u.c[2],u.c[3]);

    return 0;
}

5. 什么是协议

5.1 协议的实质

协议就像我们在学校需要遵守的规矩一样,网络通信也是如此,只有当服务器与客户端均遵守相同的规矩(协议)它们之间才能完成通信。

5.2 协议的分类

公有协议:大部分人都遵守的规矩。

私有协议:部分人遵守的协议。例如对讲机,远程监控使用公有协议就会存在安全问题,一般数据链路层和物理层均使用私有协议。

6. 传输层协议之TCP通信

6.1 TCP通信编程模型

服务器(server) 客户端(client)
        1. 创建socket            1. 创建socket
        2. 确定服务器协议地址簇           2. 获取服务器协议地址簇
        3. 绑定
        4. 监听
        5. 接受连接            3.  连接服务器
        6. 通信            4. 通信
        7. 断开连接              5. 断开连接

6.2 TCP实现简单通信

6.2.1 Server端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>

int serverSocket,clientSocket;
void hand(int val){
    //7. 关闭连接
    close(serverSocket);
    close(clientSocket);
    printf("bye bye!\n");
    exit(0);
}
int main(int argc,char* argv[]){
    if(argc != 3) printf("请输入ip地址和端口号!\n"),exit(0);
    printf("ip: %s     port:%d\n",argv[1],atoi(argv[2]));

    signal(SIGINT,hand);

    //1. 创建socket 参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
    serverSocket = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == serverSocket) printf("创建socket失败:%m\n"),exit(-1);
    printf("创建socket成功!\n");

    //2. 创建服务器协议地址簇
    struct sockaddr_in sAddr = { 0 };
    sAddr.sin_family = AF_INET;        //协议类型 和socket函数第一个参数一致
    sAddr.sin_addr.s_addr = inet_addr(argv[1]);  //将字符串转整数
    sAddr.sin_port = htons(atoi(argv[2]));    //将字符串转整数,再将小端转换成大端

    //3. 绑定服务器协议地址簇
    int r = bind(serverSocket,(struct sockaddr*)&sAddr,sizeof sAddr);
    if(-1 == r) printf("绑定失败:%m\n"),close(serverSocket),exit(-2);
    printf("绑定成功!\n");

    //4. 监听
    r = listen(serverSocket,10);
    if(-1 == r) printf("监听失败:%m\n"),close(serverSocket),exit(-3);
    printf("监听成功!\n");

    //5. 接收客户端连接
    struct sockaddr_in cAddr = {0};
    int len = sizeof(sAddr);
    clientSocket = accept(serverSocket,(struct sockaddr*)&cAddr,&len);
    if(-1 == clientSocket) printf("接收客户端连接失败:%m\n"),close(serverSocket),exit(-1);
    printf("有客户端连接上服务器了: %s\n",inet_ntoa(cAddr.sin_addr));

    //6. 通信
    char buff[256] = {0};
    while(1){
        r = recv(clientSocket,buff,255,0);
        if(r > 0){
            buff[r] = 0;
            printf("客户端说>> %s\n",buff);
        }
    }

    return 0;
}

6.2.2 Client端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>

int clientSocket;
void hand(int val){
    //5. 关闭连接
    close(clientSocket);
    printf("bye bye!\n");
    exit(0);
}
int main(int argc,char* argv[]){
    if(argc != 3) printf("请输入ip地址和端口号!\n"),exit(0);
    printf("ip: %s     port:%d\n",argv[1],atoi(argv[2]));

    signal(SIGINT,hand);

    //1. 创建socket 参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
    clientSocket = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == clientSocket) printf("创建socket失败:%m\n"),exit(-1);
    printf("创建socket成功!\n");

    //2. 创建服务器协议地址簇
    struct sockaddr_in cAddr = { 0 };
    cAddr.sin_family = AF_INET;
    cAddr.sin_addr.s_addr = inet_addr(argv[1]);  //将字符串转整数
    cAddr.sin_port = htons(atoi(argv[2]));    //将字符串转整数,再将小端转换成大端

    //3.连接服务器
    int r = connect(clientSocket,(struct sockaddr*)&cAddr,sizeof cAddr);
    if(-1 == r) printf("连接服务器失败:%m\n"),close(clientSocket),exit(-2);
    printf("连接服务器成功!\n");


    //4. 通信
    char buff[256] = {0};
    while(1){
        printf("你想要发送:");
        scanf("%s",buff);
        send(clientSocket,buff,strlen(buff),0);
    }

    return 0;
}

6.3 TCP实现文件传输

6.3.1 实现连接后,文件传输步骤

接收端(Server) 发送端(Client)
1. 等待客户端发送 1. 发送文件名
2. 接收文件名并创建文件 2. 获取文件大小并发送
3. 接收文件大小并打开文件 3. 打开文件准备读取发送
4. 循环接收并写入文件 4. 循环读取文件并发送文件内容
5. 写入数据完毕,关闭文件和连接 5.  发送数据完毕,关闭文件和连接

6.3.2 server(接收文件)端

//Server端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <arpa/inet.h>

int serverSocket,clientSocket;

int main(){

    //1. 创建socket  
    serverSocket = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == serverSocket) printf("创建socket失败:%m\n"),exit(-1);
    printf("创建socket成功!\n");

    //2. 创建服务器协议地址簇
    struct sockaddr_in sAddr = {0};
    sAddr.sin_family = AF_INET; 
    sAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    sAddr.sin_port = htons(9527);  

    //3.绑定
    int r = bind(serverSocket,(struct sockaddr*)&sAddr,sizeof sAddr);
    if(-1 == r) printf("绑定失败:%m\n"),close(serverSocket),exit(-2);
    printf("绑定成功!\n");

    //4.监听
    r = listen(serverSocket,10);
    if(-1 == r) printf("监听失败:%m\n"),close(serverSocket),exit(-2);
    printf("监听成功!\n");

    //5.等待客户端连接
    struct sockaddr_in cAddr = {0};
    int len = sizeof(cAddr);
    clientSocket = accept(serverSocket,
        (struct sockaddr*)&cAddr,&len);
    if(-1 == clientSocket) printf("服务器崩溃:%m\n"),close(serverSocket),exit(-3);
    printf("有客户端连接上服务器了:%s\n",inet_ntoa(cAddr.sin_addr));

    //6. 通信
    char fileName[256] = {0};
    int fileSize = 0;
    char buff[1024] = {0};
    int fileCount; //统计写入文件内容的大小

    sleep(2);
    //6.1 接收文件名
    r = recv(clientSocket,fileName,255,0);
    if(r > 0){
        printf(">>>>>>%d\n",r);
        printf("接收到的文件名为: %s\n",fileName);
    }

    sleep(2);
    //6.2 接收文件大小
    r = recv(clientSocket,(int*)&fileSize,4,0);
    if(r == 4){
        printf("文件大小r>>> %d\n",r);
        printf("接收到的文件大小为: %d\n",fileSize);
    }
    //6.3 创建文件
    int fd = open(fileName,O_CREAT | O_WRONLY,0666);
    if(-1 == fd) printf("创建文件失败:%m\n"),
        close(serverSocket),close(clientSocket),exit(-4);

    sleep(2);
    //6.4 接收信息并写入文件
    while(1){
        r = recv(clientSocket,buff,1024,0);
        if(r > 0){
            write(fd,buff,r);
            fileCount += r;
            if(fileCount >= fileSize)
                break;
        }
    }

    //7. 关闭文件以及关闭连接
    sleep(1);
    close(fd);
    close(serverSocket);
    close(clientSocket);
    printf("文件接收完毕!\n");

    return 0;
}

注: accept函数为阻塞函数

6.3.3 client(发送文件)端

//Client端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>


int clientSocket;

int main(int argc,char* argv[]){

    //1. 创建socket  
    clientSocket = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == clientSocket) printf("创建socket失败:%m\n"),exit(-1);
    printf("创建socket成功!\n");

    //2. 创建服务器协议地址簇
    struct sockaddr_in cAddr = {0};
    cAddr.sin_family = AF_INET; 
    cAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    cAddr.sin_port = htons(9527);  

    //3.连接服务器
    int r = connect(clientSocket,(struct sockaddr*)&cAddr,sizeof cAddr);
    if(-1 == r) printf("连接服务器失败:%m\n"),close(clientSocket),exit(-2);
    printf("连接服务器成功!\n");

    //4. 通信
    //4.1 打开文件
    int fd = open(argv[1],O_RDONLY,0666);
    if(-1 == fd) printf("文件打开失败:%m\n"),close(clientSocket),exit(-3);
    printf("文件打开成功!\n");

    //4.1 获取文件大小
    struct stat st = {0};
    stat(argv[1],&st);
    printf("文件大小为: %d\n",(int)st.st_size);
    printf("文件名为:%s\n",argv[1]);

    sleep(2);
    //4.2 将文件名和文件大小发送给服务器(注意先后顺序)
    send(clientSocket,argv[1],strlen(argv[1]),0);

    sleep(2);
    send(clientSocket,(char*)&st.st_size,4,0);

    //4.3 读取内容并发送
    sleep(2);
    char buff[1024] = {0};
    while(1){
        r = read(fd,buff,1024);
        if(r > 0)
            send(clientSocket,buff,r,0);
        else
            break;
    }

    //5. 关闭文件
    sleep(1);
    close(fd);
    close(clientSocket);
    printf("文件发送完毕!\n");

    return 0;
}

7. 传输层协议之UDP通信

7.1 UDP通信编程模型

服务器(Server) 客户端(Client)
1. 创建Socket 1. 创建Socket
2. 确定服务器协议地址簇 2. 获取服务器协议地址簇
3. 绑定
4. 通信 3. 通信

7.2 UDP实现简单通信

7.2.1 Server端

//Server
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>

int serverSocket;
void hand(int val){
    //5. 关闭serverSocket
    close(serverSocket);
    printf("bye bye!\n");
    exit(0);
}

int main(int argc,char* argv[]){

    if(argc != 3) printf("请输入ip地址和端口号!\n"),exit(0);
    printf("ip:%s    port:%d\n",argv[1],atoi(argv[2]));

    signal(SIGINT,hand);

    //1. 创建socket  参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
    serverSocket = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == serverSocket) printf("创建socket失败:%m\n"),exit(-1);
    printf("创建socket成功!\n");

    //2. 创建服务器协议地址簇
    struct sockaddr_in sAddr = {0};
    sAddr.sin_family = AF_INET; //协议类型 和socket函数第一个参数一致
    sAddr.sin_addr.s_addr = inet_addr(argv[1]); //将字符串转整数
    sAddr.sin_port = htons(atoi(argv[2]));  //整数转整数 小端转大端

    //3.绑定
    int r = bind(serverSocket,(struct sockaddr*)&sAddr,sizeof sAddr);
    if(-1 == r) printf("绑定失败:%m\n"),close(serverSocket),exit(-2);
    printf("绑定成功!\n");

    //4.通信
    char buff[256];
    struct sockaddr_in cAddr = {0};
    int len = sizeof(cAddr);

    while(1){
        //如果还需要向客户端发送东西用recvfrom
        //udp精髓  向一个协议地址簇发东西

        //收消息
        r = recvfrom(serverSocket,buff,255,0,(struct sockaddr*)&cAddr,&len);
        if(r > 0){
            buff[r] = 0;  //添加字符串结束符号
            printf(">> %s\n",buff);
        }
        printf("你想对客户端说什么: ");
            memset(buff,256,0);
            scanf("%s",buff);
            sendto(serverSocket,buff,strlen(buff),0,
                (struct sockaddr*)&cAddr,sizeof cAddr);
    }

    return 0;
}

7.2.2 Client端

//Client
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>

int clientSocket;
void hand(int val){
    //4. 结束
    close(clientSocket);
    printf("bye bye!\n");
    exit(0);
}

int main(int argc,char* argv[]){
    if(argc != 3) printf("请输入ip地址和端口号!\n"),exit(0);
    printf("ip:%s    port:%d\n",argv[1],atoi(argv[2]));

    signal(SIGINT,hand);

    //1. 创建socket  参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
    clientSocket = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == clientSocket) printf("创建socket失败:%m\n"),exit(-1);
    printf("创建socket成功!\n");
    //2. 创建服务器协议地址簇
    struct sockaddr_in cAddr = {0};
    cAddr.sin_family = AF_INET; //协议类型 和socket函数第一个参数一致
    cAddr.sin_addr.s_addr = inet_addr(argv[1]); //将字符串转整数
    cAddr.sin_port = htons(atoi(argv[2]));  //整数转整数 小端转大端

    //3.通信
    char buff[256];
    char temp[256];
    int r;
    int len = sizeof cAddr;
    while(1){
        //发消息
        printf("你想发送什么: ");
        scanf("%s",buff);

        sendto(clientSocket,buff,strlen(buff),0,
            (struct sockaddr*)&cAddr,len);

        //收消息
        r = recvfrom(clientSocket,temp,255,0,
            (struct sockaddr*)&cAddr,&len);

        if(r > 0){
            temp[r] = 0;
            printf("服务器发来信息>> %s\n",temp);
        }

    }

    return 0;
}

这样就实现了傻瓜式的一应一答的双向通信

7.3 UDP实现文件传输

7.3.1 Server(文件接收)端

//Server端(文件接收)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>

int serverSocket;

int main(){

    //1. 创建socket  
    serverSocket = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == serverSocket) printf("创建socket失败:%m\n"),exit(-1);
    printf("创建socket成功!\n");

    //2. 创建服务器协议地址簇
    struct sockaddr_in sAddr = {0};
    sAddr.sin_family = AF_INET; //协议类型 和socket函数第一个参数一致
    sAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //将字符串转整数
    sAddr.sin_port = htons(9527);  

    //3.绑定
    int r = bind(serverSocket,(struct sockaddr*)&sAddr,sizeof sAddr);
    if(-1 == r) printf("绑定失败:%m\n"),close(serverSocket),exit(-2);
    printf("绑定成功!\n");

    //4.通信(实现文件传输)
    struct sockaddr_in cAddr = {0};
    char fileName[256] = {0};
    int fileSize = 0;
    char buff[1024] = {0};
    int fileCount; //统计写入文件内容的大小
    int len = sizeof(cAddr);

    sleep(2);
    //4.1 接收文件名
    r = recvfrom(serverSocket,fileName,255,0,
        (struct sockaddr*)&cAddr,&len);
    if(r > 0){
        printf(">>>>>>%d\n",r);
        printf("接收到的文件名为: %s\n",fileName);
    }

    sleep(2);
    //4.2 接收文件大小
    r = recvfrom(serverSocket,(int*)&fileSize,4,0,
        (struct sockaddr*)&cAddr,&len);
    if(r == 4){
        printf("文件大小r>>> %d\n",r);
        printf("接收到的文件大小为: %d\n",fileSize);
    }
    //4.3 创建文件
    int fd = open(fileName,O_CREAT | O_WRONLY,0666);
    if(-1 == fd) printf("创建文件失败:%m\n"),
        close(serverSocket),exit(-4);

    sleep(2);
    //4.4 接收信息并写入文件
    while(1){
        r = recvfrom(serverSocket,buff,1024,0,
            (struct sockaddr*)&cAddr,&len);
        if(r > 0){
            write(fd,buff,r);
            fileCount += r;
            if(fileCount >= fileSize)
                break;
        }
    }

    //5. 关闭serverSocket
    sleep(1);
    close(fd);
    close(serverSocket);
    printf("bye bye!\n");

    return 0;
}

7.3.2 Client(文件发送)端

//Client端(文件发送)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/stat.h>


int clientSocket;

int main(int argc,char* argv[]){

    //1. 创建socket  
    clientSocket = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == clientSocket) printf("创建socket失败:%m\n"),exit(-1);
    printf("创建socket成功!\n");

    //2. 创建服务器协议地址簇
    struct sockaddr_in cAddr = {0};
    cAddr.sin_family = AF_INET; //协议类型 和socket函数第一个参数一致
    cAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //将字符串转整数
    cAddr.sin_port = htons(9527);  //小端转大端

    //3.通信(文件发送)
    //3.1 打开文件
    int fd = open(argv[1],O_RDONLY,0666);
    if(-1 == fd) printf("文件打开失败:%m\n"),close(clientSocket),exit(-3);
    printf("文件打开成功!\n");

    //3.1 获取文件大小
    struct stat st = {0};
    stat(argv[1],&st);
    printf("文件大小为: %d\n",(int)st.st_size);
    printf("文件名为:%s\n",argv[1]);

    sleep(2);
    //3.2 将文件名和文件大小发送给服务器(注意先后顺序)
    sendto(clientSocket,argv[1],strlen(argv[1]),0,
        (struct sockaddr*)&cAddr,sizeof cAddr);

    sleep(2);
    sendto(clientSocket,(char*)&st.st_size,4,0,
        (struct sockaddr*)&cAddr,sizeof cAddr);

    //3.3 读取内容并发送
    sleep(2);
    char buff[1024] = {0};
    while(1){
        int r = read(fd,buff,1024);
        if(r > 0)
            sendto(clientSocket,buff,r,0,
                (struct sockaddr*)&cAddr,sizeof cAddr);
        else
            break;
    }

    //4. 文件传输完成
    sleep(1);
    close(fd);
    close(clientSocket);
    printf("bye bye!\n");

    return 0;
}

8. TCP通信与UDP通信的优缺点

8.1 TCP通信优缺点

8.1.1 优点

TCP可以建立稳定的连接,并且可靠,稳定 TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。

8.1.2 缺点

数据传输速率慢,效率低,占用系统资源高,易被攻击 TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU、内存等硬件资源。 而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。

8.2 UDP通信优缺点

8.2.1 优点

数据传输速率快,比TCP稍安全 UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。

8.2.2 缺点

不能像TCP那样建立稳定的连接并且不可靠,不稳定 因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。

相关文章
|
8天前
|
存储 网络协议 安全
用于 syslog 收集的协议:TCP、UDP、RELP
系统日志是从Linux/Unix设备及网络设备生成的日志,可通过syslog服务器集中管理。日志传输支持UDP、TCP和RELP协议。UDP无连接且不可靠,不推荐使用;TCP可靠,常用于rsyslog和syslog-ng;RELP提供可靠传输和反向确认。集中管理日志有助于故障排除和安全审计,EventLog Analyzer等工具可自动收集、解析和分析日志。
|
23天前
|
网络协议 网络性能优化 数据处理
深入解析:TCP与UDP的核心技术差异
在网络通信的世界里,TCP(传输控制协议)和UDP(用户数据报协议)是两种核心的传输层协议,它们在确保数据传输的可靠性、效率和实时性方面扮演着不同的角色。本文将深入探讨这两种协议的技术差异,并探讨它们在不同应用场景下的适用性。
64 4
|
23天前
|
监控 网络协议 网络性能优化
网络通信的核心选择:TCP与UDP协议深度解析
在网络通信领域,TCP(传输控制协议)和UDP(用户数据报协议)是两种基础且截然不同的传输层协议。它们各自的特点和适用场景对于网络工程师和开发者来说至关重要。本文将深入探讨TCP和UDP的核心区别,并分析它们在实际应用中的选择依据。
52 3
|
1月前
|
网络协议 算法 网络性能优化
|
1月前
|
网络协议 SEO
TCP连接管理与UDP协议IP协议与ethernet协议
TCP、UDP、IP和Ethernet协议是网络通信的基石,各自负责不同的功能和层次。TCP通过三次握手和四次挥手实现可靠的连接管理,适用于需要数据完整性的场景;UDP提供不可靠的传输服务,适用于低延迟要求的实时通信;IP协议负责数据包的寻址和路由,是网络层的重要协议;Ethernet协议定义了局域网的数据帧传输方式,广泛应用于局域网设备之间的通信。理解这些协议的工作原理和应用场景,有助于设计和维护高效可靠的网络系统。
39 4
|
1月前
|
缓存 负载均衡 网络协议
面试:TCP、UDP如何解决丢包问题
TCP、UDP如何解决丢包问题。TCP:基于数据块传输/数据分片、对失序数据包重新排序以及去重、流量控制(滑动窗口)、拥塞控制、自主重传ARQ;UDP:程序执行后马上开始监听、控制报文大小、每个分割块的长度小于MTU
|
2月前
|
Web App开发 缓存 网络协议
不为人知的网络编程(十八):UDP比TCP高效?还真不一定!
熟悉网络编程的(尤其搞实时音视频聊天技术的)同学们都有个约定俗成的主观论调,一提起UDP和TCP,马上想到的是UDP没有TCP可靠,但UDP肯定比TCP高效。说到UDP比TCP高效,理由是什么呢?事实真是这样吗?跟着本文咱们一探究竟!
68 10
|
1月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
95 8
|
1月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
260 6
|
1月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
80 3
下一篇
DataWorks