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);
}
相关推荐
Flying_Fish_roe22 分钟前
linux-安全管理-防火墙与网络安全
linux·数据库·oracle
不见长安见晨雾32 分钟前
Linux:vim编辑技巧
linux·编辑器·vim
神秘的土鸡1 小时前
Linux中使用Docker容器构建Tomcat容器完整教程
linux·运维·服务器·docker·容器·tomcat
shuxianshrng1 小时前
大气网格化精细化监管监测系统
大数据·服务器·windows·经验分享
friklogff1 小时前
【C#生态园】构建你的C#操作系统:框架选择与实践
服务器·开发语言·c#
TravisBytes2 小时前
linux 系统是如何收发数据包
linux·运维·服务器
就这个java爽!2 小时前
JAVA网络编程【基于TCP和UDP协议】超详细!!!
java·开发语言·网络·tcp/ip·udp·eclipse·idea
KookeeyLena72 小时前
动态IP与静态IP:哪种更适合用户使用?
网络·网络协议·tcp/ip
平头哥在等你3 小时前
《计算机网络名词解释》
服务器·网络·计算机网络
德迅--文琪3 小时前
SCDN是服务器吗?SCDN防御服务器有什么特点?
运维·服务器