多进程和多线程简单tcp聊天程序

如果需要一个服务端可以连接多个客户端,并同时与多个(不超多listen第二个参数及最大同时并发数)客户端通信,可以利用多进程即创建子进程,子进程来完成服务端的接受和发送数据;也可以创建多个线程。对于tcp一些接口具体使用可以查看这篇博客:https://blog.csdn.net/sophia__yu/article/details/82827500
tcp客户端代码

//tcp 客户端代码
//1.创建套接字
//2.绑定地址信息
//3.向服务端发送连接请求
//4.发送数据
//5.接受数据
//6.关闭socket描述符

#include<stdio.h>
#include<error.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/socket.h>
#include<stdlib.h>

int main(int argc,char* argv[])
{
        if(argc!=3)
        {
                printf("Usage ip and port\n");
        }
        //1.创建套接字
        int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(sockfd<0)
        {
                perror("socket error");
                return -1;
        }
        //2.绑定地址信息(不推荐手动写绑定信息代码)
        //3.向服务端发送连接请求
        //int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
        struct sockaddr_in ser_addr;
        ser_addr.sin_family=AF_INET;
        ser_addr.sin_port=(htons)(atoi(argv[2]));
        ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]);//因为argv[]是char*,用atoi使字符串转成整型
        int len=sizeof(struct sockaddr_in);
        int ret=connect(sockfd,(struct sockaddr*)&ser_addr,len);
        if(ret<0)
        {
                perror("connect error");
                close(sockfd);
                return -1;
        }
        //连接成功,socket描述符里有服务端和客户端IP地址和port
        while(1)
        {
                //4.发送数据
                // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
                char buff[1024]={0};
                printf("please send\n");
                scanf("%s",buff);
                ret=send(sockfd,buff,strlen(buff),0); //默认阻塞接受数据
                if(ret<0)
                {
                        perror("send error");
                        close(sockfd);
                        return -1;
                }
                //5.接受数据
                //ssize_t recv(int sockfd, void *buf, size_t len, int flags);
                memset(buff,0x00,1024);
                ret=recv(sockfd,buff,1023,0);//默认阻塞接受数据
                if(len<0)//小于0接受失败
                {
                        perror("recv error");
                        close(sockfd);
                        continue;
                }
                else if(len==0)//等于0对端将连接断开
                {
                   perror("peer has performed an orderly shutdown");
                   close(sockfd);
                   continue;
                }
                printf("[%s:%d]say:%s\n",(inet_ntoa)(ser_addr.sin_addr),(ntohs)(ser_addr.sin_port),buff);
        }
        close(sockfd);
        return 0;
}                                                

多进程服务端代码:

//多进程的tcp服务端代码

#include<stdio.h>
#include<unistd.h>
#include<error.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<wait.h>
#include<stdlib.h>
#include<arpa/inet.h>

void profunc(int sockfd)
{
        int pid=fork();
        if(pid<0)
        {
                perror("fork error");
                close(sockfd);
                return ;
        }
        else if(pid==0){
                //子进程  接受数据和发送数据
                while(1){
                        char buff[1024]={0};
                        int len=recv(sockfd,buff,1023,0);//阻塞接受数据
                        if(len<0)
                        {
                                perror("recv error");
                                close(sockfd);
                                return ;
                        }
                        else if(len==0)
                        {
                                perror("peer shutdown");
                                close(sockfd);
            return ;
                        }
                        printf("ser say:%s\n",buff);
                        send(sockfd,"hello",5,0);//服务端默认发送hello

                }
                close(sockfd);
        }
        else
        {
                //父进程
                close(sockfd);//子进程和父进程的sockfd在不同空间,所以如果父进程不对sockfd做什么,需要关闭,但是父进程最好不对sochfd不做什么,否则无法区别发送或接
受数据是父进程还是子进程
        }
}
void sigcb(int signum)
{
        while(waitpid(-1,NULL,WNOHANG)!=0)//没有子进程退出将返回0,用循环是将等待子进程资源回收完毕
        {
        }
}
int main(int argc,char* argv[])
{
        signal(SIGCHLD,sigcb);//将SIGCHLD自定义设置为等待子进程退出功能
        if(argc!=3)
        {
                printf("Usage:./ ip  port\n");
        }
        //1.创建套接字
        int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//6
        if(sockfd<0)
        {
                perror("socket error");
                return -1;
        }
        //2.绑定地址信息
 struct sockaddr_in ser_addr;
        ser_addr.sin_family=AF_INET;
        ser_addr.sin_port=htons((atoi)(argv[2]));
        ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]);
        int len=sizeof(struct sockaddr_in);
        int ret=bind(sockfd,(struct sockaddr*)&ser_addr,len);
        if(ret<0)
        {
                perror("bind error");
                close(sockfd);
                return -1;
        }
        //3.监听,listen只是设置好socket的属性,连接成功队列最多有5个结点
        if(listen(sockfd,5)<0)
        {
                perror("losten error");
                close(sockfd);
                return -1;
        }
        //4.获取新连接的客户端信息
        //多进程,创建子进程,子进程来接受发送数据,从而实现一个服务端可以同时连接多个客户端
        while(1)
        {
                struct sockaddr_in cli_addr;
                len=sizeof(struct sockaddr_in);
                int newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,&len);
                profunc(newsockfd);
        }
        close(sockfd);
        return 0;
}

第一个客户端:
在这里插入图片描述
第二个客户端:
在这里插入图片描述
服务端:
在这里插入图片描述
多线程tcp服务端代码

//多线程的tcp服务端代码

#include<stdio.h>
#include<unistd.h>
#include<error.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<wait.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<pthread.h>

void* the_start(void* arg)
{
        int sockfd=(int)arg;
        while(1)
        {
                //接受数据
                char buff[1024]={0};
                int len=recv(sockfd,buff,1023,0);//阻塞接受数据
                if(len<0)
                {
                        perror("recv error");
                        close(sockfd);
                        return ;
                }
                else if(len==0)
                {
                        perror("peer shutdown");
                        close(sockfd);
                        return ;
                }
                printf("ser say:%s\n",buff);
                send(sockfd,"hello",5,0);//服务端默认发送hello
        }
        close(sockfd);
}
int main(int argc,char* argv[])
{
        if(argc!=3)
 {
                printf("Usage:./ ip  port\n");
        }
        //1.创建套接字
        int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//6
        if(sockfd<0)
        {
                perror("socket error");
                return -1;
        }
        //2.绑定地址信息
        struct sockaddr_in ser_addr;
        ser_addr.sin_family=AF_INET;
        ser_addr.sin_port=htons((atoi)(argv[2]));
        ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]);
        int len=sizeof(struct sockaddr_in);
        int ret=bind(sockfd,(struct sockaddr*)&ser_addr,len);
        if(ret<0)
        {
         perror("bind error");
                close(sockfd);
                return -1;
        }
        //3.监听,listen只是设置好socket的属性,连接成功队列最多有5个结点
        if(listen(sockfd,5)<0)
        {
                perror("losten error");
                close(sockfd);
                return -1;
        }
        //4.获取新连接的客户端信息
        //创建多个线程
        while(1)
        {
                struct sockaddr_in cli_addr;
                len=sizeof(struct sockaddr_in);
                int newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,&len);
                //创建线程
// // int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
                pthread_t tid;
                int ret;
                ret=pthread_create(&tid,NULL,the_start,(void*)newsockfd);
        }
        close(sockfd);
        return 0;
}

第一个客户端:
在这里插入图片描述
第二个客户端:
在这里插入图片描述
服务端:
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值