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);
}
相关推荐
追风赶月、4 分钟前
【Linux】线程概念与线程控制
linux·运维·服务器
小字节,大梦想6 分钟前
【Linux】重定向,dup
linux
CP-DD18 分钟前
Docker 容器化开发 应用
运维·docker·容器
blessing。。1 小时前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
2202_754421541 小时前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
努力的悟空2 小时前
国土变更调查拓扑错误自动化修复工具的研究
运维·自动化
运维&陈同学2 小时前
【zookeeper03】消息队列与微服务之zookeeper集群部署
linux·微服务·zookeeper·云原生·消息队列·云计算·java-zookeeper
hgdlip2 小时前
主IP地址与从IP地址:深入解析与应用探讨
网络·网络协议·tcp/ip
旦沐已成舟2 小时前
DevOps-Jenkins-新手入门级
服务器
今天我刷leetcode了吗3 小时前
docker 配置同宿主机共同网段的IP 同时通过通网段的另一个电脑实现远程连接docker
tcp/ip·docker·电脑