当前位置: 首页 > news >正文

linux编程----网络通信(TCP)

1.TCP特点

1.面向数据流;

2.有连接通信;

3.安全可靠的通信方式;

4.机制复杂,网络资源开销大;

5.本质只能实现一对一的通信(可使用TCP的并发方式实现一对多通信);

2.TCP的三次握手与四次挥手

1.TCP的三次握手

TCP建立连接时,需要进行三次握手,以确保收发双方通信之前都已就绪;

2.TCP的四次挥手

TCP断开连接时,需要四次挥手,以确保断开连接前双方都以通信结束;

SYN:请求建立连接标志;

FIN:请求断开连接标志;

ACK:响应报文标志位;

3.TCP的编程流程

int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:请求与服务端建立连接
参数:
sockfd:套接字
addr:要连接的服务端的地址信息
addrlen:服务端地址大小
返回值:
成功:0
失败:-1

 ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:发送网络数据
参数:
sockfd:网络套接字
buf:要发送的数据首地址
len:发送的字节数
flags:0 :按照默认方式发送
返回值:
成功:实际发送的字节数
失败:-1

int listen(int sockfd, int backlog);
功能:监听建立三次握手的客户端
参数:
sockfd:监听套接字
backlog:最大允许监听的客户端个数
返回值:
成功:0
失败:-1

int accept(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);
功能:接收建立三次握手的客户端,并产生一个通讯套接字
参数:
socket:监听套接字
address:客户端的地址信息
address_len:客户端地址长的指针
返回值:
成功:通讯套接字
失败:-1


ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:从网络套接字上接收数据
参数:
sockfd:通讯套接字
buf:存放接收数据的首地址
len:期望接收到的字节数
flag : 0:默认方式接收(阻塞)
返回值:
成功:实际接收到的字节数
失败:-1
对方断开连接:0

4.TCP的粘包问题

TCP粘包问题:发送方应用层发送的多包数据,将来在接收方可能一次读到,多包数据产生了粘连。

      原因:
1. 发送方速度较快,TCP底层可能对多包数据进行重新组帧;
2. 接收方数据处理速度较慢,导致多包数据在接收缓冲区缓存,应用层读时,一次将多包数据读出。

     
解决粘包问题的常用方法:

1.  调整发送速率
2.  发送指定大小,将来接收方也接受指定大小。
结构体
注意:
1. 跨平台之间的数据传输时,注意结构体对齐问题。
struct a
{
char a;
int b;
long c;
};
32bits平台《--》64位平台

         3. 应用层位发送的数据增加分隔符,利用分隔符解析
hello world\nhow are you\n

         4. 封装自定义数据帧格式进行发送(协议),严格根据协议进行解析。

AA  C0  00 00 00 F0 00 BB 10 A0  00 00 00 10 校验 BB  AA  C0  00 00 00 F0 00 BB 10 A0  00 00 00 10 校验 BB AA  C0  00 00 00 F0 00 BB 10 A0  00 00 00 10 校验 BB

帧头:AA
帧尾:BB
有效数据长度:C0
有效数据:00 00 00 F0 00 BB 10 A0  00 00 00 10
校验:
8位和校验
16位和校验
CRC校验

5.代码练习

1. tcp实现图片的传输

//客户端
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>int main(int argc, char const *argv[])
{if(argc != 2){printf("./a.out <filename>\n");return -1;}int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return -1;}struct sockaddr_in sockaddr;sockaddr.sin_family = AF_INET;sockaddr.sin_port = htons(50002);sockaddr.sin_addr.s_addr = inet_addr("192.168.0.139");int connfd = connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));int fd = open(argv[1], O_RDONLY);if(fd < 0){perror("open error");return -1;}char buf[1024] = {0};int ret = 0;do{   ret = read(fd, buf, sizeof(buf));size_t conter = send(sockfd, buf, ret, 0);}while(ret > 0);close(fd);close(sockfd);return 0;
}//服务端
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>int main(int argc, char const *argv[])
{if(argc != 2){printf("./a.out <filename>\n");return -1;}int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return -1;}struct sockaddr_in sockaddr;sockaddr.sin_family = AF_INET;sockaddr.sin_port = htons(50002);sockaddr.sin_addr.s_addr = inet_addr("192.168.0.139");int ret = bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));if(ret < 0){perror("bind error");return -1;}int n = listen(sockfd, 10);if(n < 0){perror("listen error");return -1;}struct sockaddr_in dest_sockaddr;socklen_t len = sizeof(dest_sockaddr);int connfd = accept(sockfd, (struct sockaddr *)&dest_sockaddr, &len);printf("[%s][%d] online\n", inet_ntoa(dest_sockaddr.sin_addr), ntohs(dest_sockaddr.sin_port));int fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, 0664);if(fd < 0){perror("open error");return -1;}char buf[1024] = {0};ssize_t cont = 0;do{   memset(buf, 0, sizeof(buf));cont = recv(connfd, buf, sizeof(buf), 0);write(fd, buf, cont);   }while(cont > 0);close(connfd);close(sockfd);return 0;
}

2. tcp实现全双工聊天

//客户端A:
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>int sockfd = 0;
struct sockaddr_in sockaddr;int send_t()
{char buf[1024] = {0};while(1){   fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;size_t conter = send(sockfd, buf, strlen(buf), 0);if(conter > 0){printf("conter=%ld\n", conter);}if(conter < 0){perror("send error");return -1;}}close(sockfd);
}int recv_t()
{char buf[1024] = {0};do{   memset(buf, 0, sizeof(buf));ssize_t cont = recv(sockfd, buf, sizeof(buf), 0);if(cont > 0){printf("cont = %ld, buf = %s\n", cont, buf);}if(cont < 0){perror("send error");return -1;}  }while(1);close(sockfd);
}int main(int argc, char const *argv[])
{sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return -1;}sockaddr.sin_family = AF_INET;sockaddr.sin_port = htons(50001);sockaddr.sin_addr.s_addr = inet_addr("192.168.0.139");int connfd = connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));//send_t();pid_t pid = fork();if(pid > 0){send_t(); }else if(pid == 0){recv_t(); }else{perror("fork error");return -1;}return 0;
}//服务端B
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>struct sockaddr_in dest_sockaddr;
socklen_t len = sizeof(dest_sockaddr);
int sockfd = 0;
int connfd = 0;int recv_t()
{char buf[1024] = {0};do{   memset(buf, 0, sizeof(buf));ssize_t cont = recv(connfd, buf, sizeof(buf), 0);if(cont > 0){printf("cont = %ld, buf = %s\n", cont, buf);}if(cont < 0){perror("send error");return -1;}  }while(1);close(connfd);close(sockfd);
}int send_t()
{   char buf[1024] = {0};while(1){   fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;size_t conter = send(connfd, buf, strlen(buf), 0);if(conter > 0){printf("conter=%ld\n", conter);}if(conter < 0){perror("send error");return -1;}}close(connfd);close(sockfd);
}int main(int argc, char const *argv[])
{sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return -1;}struct sockaddr_in sockaddr;sockaddr.sin_family = AF_INET;sockaddr.sin_port = htons(50001);sockaddr.sin_addr.s_addr = inet_addr("192.168.0.139");int ret = bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));if(ret < 0){perror("bind error");return -1;}int n = listen(sockfd, 10);if(n < 0){perror("listen error");return -1;}connfd = accept(sockfd, (struct sockaddr *)&dest_sockaddr, &len);printf("[%s][%d] online\n", inet_ntoa(dest_sockaddr.sin_addr), ntohs(dest_sockaddr.sin_port));//recv_t();pid_t pid = fork();if(pid > 0){recv_t();}else if(pid == 0){send_t();}else {perror("fork error");return -1;}return 0;
}

http://www.dtcms.com/a/346651.html

相关文章:

  • 利用Prometheus监控服务器相关数据
  • SpringBoot自动配置原理解析
  • 本地文件夹即时变身 Web 服务器(文件服务器)
  • Linux问答题:归档和传输文件
  • Reactor 反应堆模式
  • 《解构React Server Components:服务端序列化与流式传输的底层逻辑》
  • 为什么在WHERE子句里使用函数,会让索引失效
  • 中农具身导航赋能智慧农业!AgriVLN:农业机器人的视觉语言导航
  • 【数据结构】计数排序:有时比快排还快的整数排序法
  • Linux PCI 子系统:工作原理与实现机制深度分析
  • 并查集详解
  • 第三阶段数据库-9:循环,编号,游标,分页
  • 【数据分析】宏基因组荟萃分析(Meta-analysis)的应用与实操指南
  • ES作为推荐库的设计原理
  • 配置npm国内源(包含主流npm镜像源地址)
  • Docker之nginx安装
  • 青少年机器人技术(五级)等级考试试卷(2020年9月)
  • docker的数据管理
  • 工作空间与功能包
  • 解读66页数字化转型数据中台规划应用实践解决方案【附全文阅读】
  • Q/DR/CX7.2-2020 是中国企业标准体系中
  • 【2025CVPR-目标检测方向】UniMamba:基于激光雷达的3D目标检测,采用分组高效曼巴语进行统一空间信道表示学习
  • Qt + windows+exe+msvc打包教程
  • 今日科技热点 | 量子计算突破、AI芯片与5G加速行业变革
  • Elasticsearch:什么是神经网络?
  • 算法训练营day59 图论⑨ dijkstra(堆优化版)精讲、Bellman_ford 算法精讲
  • Redis Set 类型详解:从基础命令到实战应用
  • OpenJDK 17 安全点检查机制深入解析
  • 【AI基础:神经网络】16、神经网络的生理学根基:从人脑结构到AI架构,揭秘道法自然的智能密码
  • Photoshop CS6精简版轻量级,Photoshop CS6绿色免安装,Photoshop CS6安装教程