socket网络编程——多线程并发,多客户端与服务器交互

多客户端与服务器数据互发

基于上几节描述,本节进行多客户端与服务器的数据互发。

创建服务器,每当一个新的客户端与服务器建立连接后,创建新的线程用于与客户端进行数据交互与处理;每个客户端同样创建线程,主线程用于发数据,子线程用于读数据



server端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>  //IP转换函数
#include <ctype.h>  //toupper函数头文件
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <netinet/in.h>
#include <pthread.h>  //线程头文件

#include "wrap.h"  // 

#define MAXLINE 800   //client.c与server.c中的数据传输的buf的size 
#define INET_ADDRSTRLEN 16
#define SERV_PORT 6666


struct s_info{  //定义一个结构体,将客户端的地址与connfd进行捆绑
    struct sockaddr_in cliaddr;
    int connfd;
};

//服务器端写数据
void *do_work_back(void* arg_back)
{
    int n,i;
    struct s_info *ts_back=(struct s_info*)arg_back;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    
    while(1)
    {
        fgets(buf,MAXLINE,stdin);
                printf("Data to client ip: %s,port: %d\n",inet_ntop(AF_INET,&ts_back->cliaddr.sin_addr.s_addr,str, sizeof(str)),ntohs(ts_back->cliaddr.sin_port));
        Write(ts_back->connfd,buf,MAXLINE); //写回客户端  
    }
    Close(ts_back->connfd);
    pthread_exit(0);  
}

//服务器端读数据
void *do_work(void* arg)
{
    int n,i;
    struct s_info *ts=(struct s_info*)arg;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];

    while(1)
    {
        n=Read(ts->connfd,buf,MAXLINE);
        if(n==0)
        {
                        printf("The [client ip: %s,port: %d] has beens closed!\n",inet_ntop(AF_INET,&ts->cliaddr.sin_addr.s_addr,str, sizeof(str)),ntohs(ts->cliaddr.sin_port));
            break;
        }
                //show client IP+PORT
                printf("Data from client ip: %s,port: %d\n",inet_ntop(AF_INET,&ts->cliaddr.sin_addr.s_addr,str, sizeof(str)),ntohs(ts->cliaddr.sin_port));
        printf("Data from client is:%s",buf);
    }
    Close(ts->connfd);
    pthread_exit(0);  
}

    
int main(void)
{
        struct sockaddr_in servaddr, cliaddr;
        socklen_t cliaddr_len;
        int listenfd, connfd;
        char buf[MAXLINE];
                char str[MAXLINE];
        int i, n;
                pthread_t tid,tid_back;  //定义pthread_t型的变量
            struct s_info ts[100]; //创建结构体数组,设置可接收的客户端上限
            i=0;

        listenfd = Socket(AF_INET, SOCK_STREAM, 0);

        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(SERV_PORT);
        Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
        Listen(listenfd, 20);

            printf("Accepting connections ...\n");
                cliaddr_len=sizeof(cliaddr);
     
                 while(1)
                {
                         connfd=Accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len);
            //每收到一个客户端的链接,将该建立连接的客户端的地址与创建的文件描述符锁定至创建的结构体数组ts[i]中,并作为另起线程的参数
                         ts[i].cliaddr=cliaddr;
             ts[i].connfd=connfd;
            
             pthread_create(&tid,NULL,do_work,(void*)&ts[i]);  //将ts[i]作为参数传递给子线程do_work()函数
             pthread_detach(tid);     //将线程设置成分离的,线程运行结束后会自动释放所有资源
                        pthread_create(&tid_back,NULL,do_work_back,(void*)&ts[i]);
                    pthread_detach(tid_back);    
             i++;  //起下一线程
                   }

                pthread_exit(0);
}

client 端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>  //线程头文件

#include "wrap.h"

#define MAXLINE 800
#define SERV_PORT 6666


struct s_info{  //定义一个结构体,将客户端的地址与connfd进行捆绑
    struct sockaddr_in servaddr;
    int sockfd;
};


void *do_work_client(void *arg)
{
    int n;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    
    struct s_info *ts=(struct s_info *)arg;  //将(void *)类型的数据强转成(struct s_info型)
    while(1)
    {
        n=Read(ts->sockfd,buf,MAXLINE);
                if(n==0)
        {
                        printf("The server has beens closed\n");
            break;
        }
        printf("Data from server:%s",buf);
                memset(buf,0,sizeof(buf));  
    }
    
    Close(ts->sockfd);
    pthread_exit(0);
}


int main(void)
{
        struct sockaddr_in servaddr;
        char buf[MAXLINE];
        int sockfd;
            pthread_t tid; //定义pthread_t型变量
        struct s_info ts;
    
        sockfd = Socket(AF_INET, SOCK_STREAM, 0);

        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        inet_pton(AF_INET, "127.127.0.1", &servaddr.sin_addr);
        servaddr.sin_port = htons(SERV_PORT);

        Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
            
            ts.servaddr=servaddr;
            ts.sockfd=sockfd;
                //将服务器端的地址及客服端的文件描述符作为参数传递给子线程do_work_client()函数
                 pthread_create(&tid,NULL,do_work_client,(void*)&ts); //ts的数据以void的类型进行数据传输 
                   pthread_detach(tid);     //将线程设置成分离的,线程运行结束后会自动释放所有资源

        while(1)
        {
        fgets(buf,sizeof(buf),stdin);
        Write(sockfd,buf, strlen(buf));
        }
        Close(sockfd);
        return 0;
}

编译

//生成可执行文件server
gcc server.c wrap.c -o server -lpthread 
//生成可执行文件client
gcc client.c wrap.c -o client -lpthread 

运行输出

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值