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

22-LINUX--多线程and多进程TCP连接

一.TCP连接基础知识

1.套接字

        所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口  

套接字 = IP + 端口

知名端口:1024以内的端口,不能随便用

保留端口:1024-4096

2.检查服务器端与客户端之间是否正常连接

查看发送缓冲区,接收缓冲区未被接收或读取的信息

netstat   -natp

3.TCP的特点

面向连接的,可靠的,流式服务

TCP的特点如何保证:tcp具有应答确认,超市重传机制,乱序重排,去重,滑动窗口进行流量控制

4.粘包

多个数据包被连续存储于连续的缓冲区中,在对数据包进行读取时无法缺点数据包之间的边界;

解决方法:1.加标记2.自己设计包头描述数据部分的大小

二.多线程TCP网络连接

ser.c

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>int socket_init();void* thread_fun(void* arg)
{int *p=(int*)arg;if(p==NULL)//传进来指针,必须判空{pthread_exit(NULL);}int c = *p;free(p);while(1){char buff[128]={0};int n=recv(c,buff,127,0);//-1失败 0对方关闭连接if(n <=0){break;}printf("buff(%d)=%s\n",c,buff);send(c,"ok",2,0);}printf("buff(%d) close\n",c);close(c);pthread_exit(NULL);
}int main()
{int sockfd =socket_init();if(sockfd ==-1){exit(1);}while(1){int c = accept(sockfd,NULL,NULL);//c与用户交互的关键值if(c<0){continue;}printf("accept c =%d\n",c);pthread_t id;int* p =(int*)malloc(sizeof(int));*p = c;pthread_create(&id,NULL,thread_fun,(void*)p);}
}
int socket_init()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){return -1;}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("bind err\n");return -1;}res = listen(sockfd,5);if(res ==-1){return -1;}return sockfd;
}89,1         底端

上述ser.c代码中,在客户端退出连接后,没有回收子线程的空间,通常需要使用pthread_join回收空间,但是这样会无法使客户端同时连接服务器,所以使用下列改进代码,在关闭连接时,即可回收空间,无需使用join.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>int socket_init();void* thread_fun(void* arg)
{int *p=(int*)arg;if(p==NULL)//传进来指针,必须判空{pthread_exit(NULL);}int c = *p;free(p);while(1){char buff[128]={0};int n=recv(c,buff,127,0);//-1失败 0对方关闭连接if(n <=0){break;}printf("buff(%d)=%s\n",c,buff);send(c,"ok",2,0);}printf("buff(%d) close\n",c);close(c);pthread_exit(NULL);
}
nt main()
{int sockfd =socket_init();if(sockfd ==-1){exit(1);}while(1){int c = accept(sockfd,NULL,NULL);//c与用户交互的关键值if(c<0){continue;}printf("accept c =%d\n",c);pthread_t id;pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//设>置脱离属性,不需要执行joinint* p =(int*)malloc(sizeof(int));*p = c;pthread_create(&id,NULL,&attr,thread_fun,(void*)p);}
}
int socket_init()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){return -1;}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res==-1){printf("bind err\n");return -1;}res = listen(sockfd,5);if(res ==-1){return -1;}return sockfd;
}92,1         底端

cli.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){exit(1);}struct sockaddr_in saddr;//代表服务器的端口memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res == -1){printf("connct err\n");exit(1);}while(1){printf("input: ");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;}send(sockfd,buff,strlen(buff)-1,0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("buff=%s\n",buff);}close(sockfd);exit(0);
}

三.TCP多进程连接

ser.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<pthread.h>
#include<assert.h>
#include<signal.h>
#include<sys/wait.h>
void fun(int sig)
{wait(NULL);
}
int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);//tcp if(sockfd ==-1){exit(1);}struct sockaddr_in saddr,caddr; // saddr-ser  caddr-climemset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr =inet_addr("127.0.0.1");int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res == -1){printf("bind err\n");exit(1);}listen(sockfd,5);signal(SIGCHLD,fun);
//signal(SIGCHLD,SIG_IGN);//LINUX系统处理僵死进程特有的方法while(1){int len = sizeof(caddr);int c = accept(sockfd,(struct sockaddr*)&caddr,&len);if(c<0){continue;}printf("accept c =%d\n",c);pid_t pid = fork();assert(pid != -1);if(pid == 0){close(sockfd);//子进程不需要sockfdwhile(1){char buff[128] = {0};int n=recv(c,buff,127,0);if(n<=0){break;}printf("recv(%d)=%s\n",c,buff);send(c,"ok",2,0);}close(c);printf("client(%d) close\n",c);exit(0);}close(c);//父进程关闭连接,c引用计数减1}
}int socket_init()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd ==-1){return -1;}struct sockaddr_in saddr,caddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("137.0.0.1");int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res == -1){return -1;}listen(sockfd,5);return sockfd;
}96,1         底端

cli.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){exit(1);}struct sockaddr_in saddr;//代表服务器的端口memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if(res == -1){printf("connct err\n");exit(1);}while(1){printf("input: ");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;}send(sockfd,buff,strlen(buff)-1,0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("buff=%s\n",buff);}close(sockfd);exit(0);
}

http://www.lryc.cn/news/352050.html

相关文章:

  • 像素级创意:深入浅出PixelCNN图像合成技术
  • MyBatisPlus使用流程
  • 爬虫技术升级:如何结合DrissionPage和Auth代理插件实现数据采集
  • go 微服务框架kratos错误处理的使用方法及原理探究
  • AI播客下载:Dwarkesh Podcast(关于AI的深度访谈)
  • C++11function包装器的使用
  • Vue3判断变量和对象不为null和undefined
  • C++进阶:C++11(列表初始化、右值引用与移动构造移动赋值、可变参数模版...Args、lambda表达式、function包装器)
  • Vue.js Promise 与 async/await 的比较
  • Qt 报错总结 No suitable kits found
  • ThingsBoard如何拆分前后端分离启动
  • 加载页面 跳转 新页面 vue
  • 中国主要城市房价指数数据集(2011-2024)
  • Creating Server TCP listening socket *:6379: listen: Unknown error
  • JUnit5标记测试用例
  • 在Windows10中重命名文件和文件夹的6种方法,有你熟悉和不熟悉的
  • Go源码--sync库(1)sync.Once和
  • 头歌OpenGauss数据库-I.复杂查询第3关:统计总成绩
  • LeetCode hot100-47-N
  • 中北大学软件学院计算机网络实验一
  • 扩散模型学习1
  • 【HTML】制作一个跟随鼠标的流畅线条引导页界面(可直接复制源码)
  • vue3父子组件、跨级组件之间的通信之provide, inject -- 通俗易懂
  • input输入多行文本,保存为.dot文件和对应的.txt文件
  • 如何让社区版IDEA变得好用
  • Hsql每日一题 | day02
  • RepOptimizer原理与代码解析(ICLR 2023)
  • 持续总结中!2024年面试必问 20 道 Redis面试题(六)
  • 【通义千问—Qwen-Agent系列2】案例分析(图像理解图文生成Agent||多模态助手|| 基于ReAct范式的数据分析Agent)
  • 10G SFP双口万兆以太网控制器,高速光口网络接口卡