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

news2024/11/24 9:37:37

一.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);
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习前端第四十三天(样式和类、元素大小和滚动、Window大小和滚动、坐标)

一、样式和类 1、className&#xff0c;classList elem.className 对应于 "class" 特性 <div id"box" class"a b" style"height: 20px;">box</div><script>const box document.getElementById("box");…

uniapp gaid-item组件增加角标的方法以及最新版本已删除角标参数的注意事项

在uniapp项目的开发中&#xff0c;列表组件gaid-item大家应该都是经常用的&#xff0c;其实组件上的角标用法也是很方便的&#xff0c;但是不熟悉的新手朋友&#xff0c;特别是用最新版的朋友可能都找不到角标方法的使用地方&#xff1a; 1.首先官方说明&#xff0c;在最新版本…

【Unity】免费的高亮插件——QuickOutline

除了常见的HighLightSystem来实现的高亮功能&#xff0c;其实还有很多的方法实现物体的高亮。 在 Unity资源商店 搜索OutLine&#xff0c;就会有很多免费好用的高亮插件。 下面介绍一下 QuickOutline这个插件&#xff0c;在 Unity资源商店 搜索到后&#xff0c;点击进去就可以…

【QGIS入门实战精品教程】13.1:导入带地理标签的航测照片

文章目录 一、数据准备二、导入带地理标签的航测照片三、导出点位shp四、生成航线一、数据准备 本实验数据位于13.1:导入带地理标签的航测照片.rar中,如下: 查看照片及相机参数信息,航测照片都带有相机参数、部分POS及地理坐标信息,如下所示: 二、导入带地理标签的航测照…

Java - AbstractQueuedSynchronizer

AQS简介 AQS全称AbstractQueuedSynchronizer&#xff0c;抽象队列同步器&#xff0c;是一个实现同步组件的基础框架。AQS使用一个int类型的成员变量state维护同步状态&#xff0c;通过内置的同步队列&#xff08;CLH锁、FIFO&#xff09;完成线程的排队工作&#xff0c;底层主…

AI大模型如何赋能智能座舱

AI 大模型如何赋能智能座舱 从上海车展上&#xff0c;我们看到由于智能座舱配置性价比较高&#xff0c;已经成为车企的核心竞争点之一&#xff0c;随着座舱硬件规模化装车&#xff0c;蔚小理、岚图、极狐等新势力开始注重座舱多模态交互&#xff0c;通过集成语音/手势/触控打造…

Vue速成学习笔记

这两天速成了一下Vue&#xff0c;在这里记录一下相关的笔记&#xff0c;之后有时间详细学Vue的时候再来回顾一下&#xff01; 一、Vue理解 1、Vue的核心特征&#xff1a;双向绑定。 在网页中&#xff0c;存在视图和数据。在Vue之前&#xff0c;需要使用JavaScript编写复杂的逻…

电脑同时配置两个版本mysql数据库常见问题

1.配置时&#xff0c;要把bin中的mysql.exe和mysqld.exe 改个名字&#xff0c;不然两个版本会重复&#xff0c;当然&#xff0c;在初始化数据库的时候&#xff0c;如果时57版本的&#xff0c;就用mysql57(已经改名的)和mysqld57 代替 mysql 和 mysqld 例如 mysql -u root -p …

Redis(十二) 持久化

文章目录 前言Redis实现数据的持久化Redis实现持久化的策略RDB手动触发RDB持久化操作自动触发RDB持久化操作 AOFAOF重写机制 前言 众所周知&#xff0c;Redis 操作数据都是在内存上操作的&#xff0c;而我们都知道内存是易失的&#xff0c;服务器重启或者主机掉电都会导致内存…

面试八股之MySQL篇4——事务篇

&#x1f308;hello&#xff0c;你好鸭&#xff0c;我是Ethan&#xff0c;一名不断学习的码农&#xff0c;很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 &#x1f3c3;人生之义&#xff0c;在于追求&#xff0c;不在成败&#xff0c;勤通…

生命线上的高效传递:了解下医院内、外网文件交互方式的革新之路

在医院的日常运营中&#xff0c;普遍采用内外网隔离的建设方式。内网集信息管理、通讯协作、资源共享、业务流程管理于一身&#xff0c;承载了医院的医疗核心业务&#xff0c;如HIS&#xff08;医院信息系统&#xff09;、LIS&#xff08;实验室信息系统&#xff09;、EMR&…

如何灵活运用keil工具进行问题分析(1)— 解决日常程序卡死问题

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘湖南区域日常实习生&#xff0c;任何区域的暑假Linux驱动实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &#xff08;2&#xff0…

山脉数组的峰顶索引 ---- 二分查找

题目链接 题目: 分析: 我们很明显, 可以从峰值位置将数组分成两段, 具有"二段性", 所以可以用二分查找因为arr是山峰数组, 不存在相等的情况如果arr[mid] > arr[mid 1], 说明mid的位置可能是峰值, 移动right mid如果arr[mid] < arr[mid 1], 说明mid的位置…

Java基础之异常(简单易懂)

异常 1.JAVA异常体系 &#xff08;1&#xff09;Throwable类(表示可抛)是所有异常和错误的超类&#xff0c;两个直接子类为Error和Exception,分别表示错误和异常;其中异常类Exception又分为运行时异常和非运行时异常&#xff0c;这两个异常有很大区别&#xff0c;运行时异常也…

【分享笔记】符尧:预训练、指令微调、对齐、专业化——论大语言模型能力的来源

分享时间&#xff1a;2023.2 目录 模型家族scaling law和涌现能力模型不同阶段pretrainingintruction tuningalignment upper bound和lower bound 模型家族 看模型要从演化家族来看&#xff0c;而不能单独看&#xff0c;很多人认为一些能力并不是RLHF激发出来的&#xff0c;而…

【区块链】智能合约漏洞测试

打开Ganache vscode打开智能合约漏洞工程 合约内容 pragma solidity >0.8.3;contract EtherStore {mapping(address > uint) public balances;function deposit() public payable {balances[msg.sender] msg.value;emit Balance(balances[msg.sender]);}function with…

前端工程化07-常见的包管理工具npm、yarn、cnpm、npx、pnpm

8、包管理工具 8.1、包管理工具概述 npm包管理工具、在安装node的时候这个东西就已经安装过了&#xff0c;通过npm去管理包的时候这个时候回有一个配置文件叫做package.json,他是以json的方式来书写对应的一个配置文件&#xff0c;这个配置文件是可以添加特别多的一些字段的&…

d3dx9_41.dll是个什么东西?d3dx9_41.dll文件丢失的解决方法

随着软件技术的不断发展&#xff0c;电脑用户可能会遇到各种系统错误和问题&#xff0c;其中之一就是动态链接库&#xff08;DLL&#xff09;文件的丢失。d3dx9_41.dll文件丢失是一个常见的问题&#xff0c;它通常会在运行依赖于DirectX图形技术的游戏或应用程序时被报告。这个…

MySQL中如何知道数据库表中所有表的字段的排序规则是什么?

查看所有表的字段及其排序规则&#xff1a; 你可以查询 information_schema 数据库中的 COLUMNS 表&#xff0c;来获取所有表的字段及其排序规则。以下是一个示例查询&#xff1a; SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLLATION_NAME FROM information_schema.COL…

影视解说5.0版零基础视频课程

课程简介 现在还能做解说吗、不会写解说文案怎么解决、不会配音怎么解决、如何找到合适的素材资源、如何变现…这是很多想做解说的伙伴最关心的几大问题。比如文案&#xff0c;我们推荐一个网站&#xff0c;10分钟搞定一篇文案&#xff0c;配音可以真人配音也可以软件配音。5.…