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);
}
相关推荐
九河云2 小时前
AWS账号注册费用详解:新用户是否需要付费?
服务器·云计算·aws
Lary_Rock2 小时前
RK3576 LINUX RKNN SDK 测试
linux·运维·服务器
幺零九零零3 小时前
【计算机网络】TCP协议面试常考(一)
服务器·tcp/ip·计算机网络
云飞云共享云桌面4 小时前
8位机械工程师如何共享一台图形工作站算力?
linux·服务器·网络
Peter_chq4 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
一坨阿亮5 小时前
Linux 使用中的问题
linux·运维
dsywws6 小时前
Linux学习笔记之vim入门
linux·笔记·学习
幺零九零零7 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
wclass-zhengge7 小时前
Docker篇(Docker Compose)
运维·docker·容器
李启柱7 小时前
项目开发流程规范文档
运维·软件构建·个人开发·设计规范