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);//设>置脱离属性,不需要执行join
                int* 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-cli
        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");
                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);//子进程不需要sockfd
                        while(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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/633483.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Map遍历、反射、GC

map的遍历 用foreach遍历 HashMap<Character,Integer> map new HashMap<>();map.put(A,2);map.put(B,3);map.put(C,3);for (Map.Entry<Character,Integer> entry: map.entrySet()) {char key entry.getKey();int value entry.getValue();System.out.prin…

CF451E: Devu and Flowers(容斥原理 + 考虑反面 + golang组合模版)

题目截图 题目翻译 题目分析 正难则反&#xff0c;考虑所有不符合的例子 由于n很小&#xff0c;所以可以状态压缩二进制遍历完全部不符合例子的组合 对于不符合的例子&#xff0c;假设其中第i个不符合&#xff0c;那么就消耗掉fi 1个球 以此类推&#xff0c;减剩下s2个球 这时…

Android正向开发实现客户端证书认证

前言 如果第三方模块被混淆,那hook方式均不能生效。这时就需要根据系统包去定位校验的函数,因此需要对安卓开发者是如何实现客户端证书校验的有一定了解,接下来就介绍这部分内容。 开发者实现客户端证书校验的本质是:证书/密钥 + 代码。 在形式上有:证书校验、公钥校验和…

Anthropic绘制出了大型语言模型的思维图:大型语言模型到底是如何工作

今天&#xff0c;我们报告了在理解人工智能模型的内部运作方面取得的重大进展。我们已经确定了如何在 Claude Sonnet&#xff08;我们部署的大型语言模型之一&#xff09;中表示数百万个概念。这是对现代生产级大型语言模型的首次详细了解。这种可解释性的发现将来可以帮助我们…

Hadoop 客户端 FileSystem加载过程

如何使用hadoop客户端 public class testCreate {public static void main(String[] args) throws IOException {System.setProperty("HADOOP_USER_NAME", "hdfs");String pathStr "/home/hdp/shanshajia";Path path new Path(pathStr);Confi…

AWS安全性身份和合规性之Artifact

AWS Artifact是对您很重要的与合规性相关的信息的首选中央资源。AWS Artifact是一项服务&#xff0c;提供了一系列用于安全合规的文档、报告和资源&#xff0c;以帮助用户满足其合规性和监管要求。它允许按需访问来自AWS和在AWS Marketplace上销售产品的ISV的安全性和合规性报告…

当他们在说业务的时候,到底在说什么

业务就是通过提供产品和服务给客户&#xff0c;以获取某种价值&#xff0c;形成业务闭环&#xff0c;并能自负盈亏。 文章会以生动形象的比喻来介绍业务到底是什么。 什么是业务&#xff1f; 业务&#xff0c;就像一场精彩的舞台剧&#xff0c;每个角色都有自己的任务和目标…

PHP生成二维码+二维码包含logo图片展示

composer require chillerlan/php-qrcode 用到的扩展自己安装&#xff08;注&#xff1a;只生成二维码只要开gd扩展就行&#xff09; 仅生成二维码看这个&#xff1a; use chillerlan\QRCode\QRCode;public function QRCode(){$qrcode new QRCode();$url "http://ww…

新建项目上传gitee

1.在项目根目录下打开黑窗口执行初始化 git init2.复制码云上新建仓库地址 3.本地仓库和远程仓库建立连接 远程仓库地址是之前复制的仓库地址&#xff0c;复制后直接在命令窗口中鼠标右键Paste即可在命令窗口粘贴出来 git remote add origin 远程仓库地址4.每次上传之前先更…

工厂模式(简单工厂模式+工厂模式)

工厂模式的目的就是将对象的创建过程隐藏起来&#xff0c;从而达到很高的灵活性&#xff0c;工厂模式分为三类&#xff1a; 简单工厂模式工厂方法模式抽象工厂模式 在没有工厂模式的时候就是&#xff0c;客户需要一辆马车&#xff0c;需要客户亲自去创建一辆马车&#xff0c;…

uniapp-自定义navigationBar

封装导航栏自定义组件 创建 nav-bar.vue <script setup>import {onReady} from dcloudio/uni-appimport {ref} from vue;const propsdefineProps([navBackgroundColor])const statusBarHeight ref()const navHeight ref()onReady(() > {uni.getSystemInfo({success…

Qt---录音

1.获取麦克风阵列&#xff1a; QList<QAudioDeviceInfo> infos QAudioDeviceInfo::availableDevices(QAudio::AudioInput);for (int i 0; i < infos.count(); i){qDebug() << infos.at(i).deviceName();} "麦克风阵列 (Realtek(R) Audio)" 2.QAudio…

利用开源工具创建WEBGIS应用

在本文中&#xff0c;我们将大致说明利用开源工具如何与服务器交互以构建交互式或动态 Web GIS。 WebGIS 应用程序已成为展示地理数据的重要模式。我们现在拥有允许用户交互的机制&#xff0c;以便用户可以选择数据&#xff0c;甚至修改或添加新数据。 什么是WEBGIS? 通过网络…

大创项目推荐 深度学习手势识别 - yolo python opencv cnn 机器视觉

文章目录 0 前言1 课题背景2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存 5 模型训练5.1 修…

用markdown(typora)画系统框图或系统结构图

markdown本身是不支持画系统框图或系统结构图的&#xff1b;但是可以参考excel的语法格式&#xff0c;用合并单元格填充背景色&#xff0c;来实现我们预期的效果&#xff1b; 源代码是html语法&#xff0c;如果有其它需求也可以自己搜索html语法&#xff0c;进行优化 <ta…

netcat一键开始瑞士军刀模式(KALI工具系列五)

目录 1、KALI LINUX简介 2、netcat工具简介 3、在KALI中使用netcat 3.1 目标主机IP&#xff08;win&#xff09; 3.2 KALI的IP 4、命令示例 4.1 测试某IP的端口是否打开 4.2 TCP扫描 4.3 UDP扫描 4.4 端口刺探 4.5 直接扫描 5、即时通信 5.1 单击对话互联 5.2 传…

单向无头链表实现

目录 1. 为什么要有链表&#xff1f; 2. 链表的种类 3. 具体功能实现 &#xff08;1&#xff09;节点结构体定义 &#xff08;2&#xff09;申请节点 &#xff08;3&#xff09;尾插 &#xff08;4&#xff09;尾删 &#xff08;5&#xff09;头插 &#xff08;6&#…

文本信息的二维码怎么做?在线制作文本二维码的3个步骤

现在通过二维码来展示文本信息是很常见的一种方式&#xff0c;可以将信息编辑好排版后生成二维码&#xff0c;其他人可以通过扫描生成的二维码来获取文本信息。这种方式传递起来更加的简单快捷&#xff0c;而且二维码可以长期提供内容展示效果降低了推广成本&#xff0c;在很多…

数据库系统概论(第5版)复习笔记

笔记的Github仓库地址 &#x1f446;这是笔记的gihub仓库&#xff0c;内容是PDF格式。 因为图片和代码块太多&#xff0c;放到CSDN太麻烦了&#xff08;比较懒&#x1f923;&#xff09; 如果感觉对各位有帮助的话欢迎点一个⭐\^o^/

Elasticsearch 加速在无服务器上构建 AI 搜索应用程序

作者&#xff1a;来自 Elastic Alvin Richards, Yaru Lin 今天&#xff0c;我们宣布推出 Elasticsearch Serverless 技术预览版&#xff0c;其功能包括&#xff1a; 以开发人员为中心的体验&#xff0c;通过直观的入门和相关代码示例简化创建人工智能驱动的搜索&#xff0c;所…