牛客网多线程socket通信案列

本文分享了一个牛客网上的多线程Socket通信案例,通过C语言实现服务器与客户端之间的通信,并利用多线程处理多个客户端的连接请求。代码详细展示了如何创建服务器与客户端、建立连接、收发数据及资源释放的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

牛客网多线程socket通信案列完善版本

刚开始自己享用for循环直接实现回收,发现还是存在问题,话不多说代码里面有很多注释。希望有改进的同学私信我。

//这是服务器的
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

// 定义最大连接数为3
const int maxLink = 3; //C里只能用#define定义常量,但C++却可以用const。

struct communPara{
    struct sockaddr_in clientInfo;
    int cfd ;
    pthread_t tid;
};
struct communPara ccp[maxLink];  //与客户端通信参数 client communication parameters

void* communication(void * arg){ 
    struct communPara* ccp=(struct communPara*)arg;
    //输出客户端信息
    char lientIP[16]={0};
    inet_ntop(AF_INET,&ccp->clientInfo.sin_addr.s_addr,lientIP,sizeof(lientIP));
    unsigned short clientPort=ntohs(ccp->clientInfo.sin_port);
    printf("client's IP is:%s,  client's port is:%d\n",lientIP,clientPort);
    sleep(0.5);
    // 1.通信
    char recvSendBuf[1024];
    while(1){
        //清空缓存
        memset(recvSendBuf,0,sizeof(recvSendBuf));
        int len = read(ccp->cfd,recvSendBuf,sizeof(recvSendBuf));
        if(len==-1){
            perror("read");
            break;//就算有问题也要去释放资源
        }else if(len>0){
            printf("server receive data: %s\n",recvSendBuf);
        }else if(len==0){
            printf("%ld客户端断开\n",ccp->tid);
            break;
        }
        write(ccp->cfd,recvSendBuf,sizeof(recvSendBuf));
    }

    // 2.释放文件描述符
    close(ccp->cfd);

    // 3.将传入的结构体清零;
    bzero(&ccp->clientInfo,sizeof(ccp->clientInfo));
    ccp->cfd=-1;
    ccp->tid=-1;
    return NULL;
}

int main() {
    char serverIP[] = {"192.168.73.100"};
    unsigned short serverPort = 9090;

    // 1.创建socket,获取连接文件描述符
    int lfd = socket(AF_INET,SOCK_STREAM,0);
    if(lfd == -1){ perror("socket");  exit(-1);}

    // 2.封装端口
    struct sockaddr_in serverInfo;
    serverInfo.sin_family = AF_INET;
    serverInfo.sin_addr.s_addr = INADDR_ANY;
    serverInfo.sin_port = htons(serverPort);

    // 3.bind绑定服务器IP和端口,和文件描述符
    int ret = bind(lfd,(struct sockaddr*) &serverInfo,sizeof(serverInfo));
    if(ret == -1){ perror("bind");  exit(-1);}

    // 4.listen监听端口
    ret = listen(lfd,maxLink);
    if(ret == -1){ perror("listen");  exit(-1);}
           
    // 初始化数据
    int max=sizeof(ccp)/sizeof(ccp[0]);
    for(int i=0;i<max;++i){
        bzero(&ccp[i],sizeof(ccp[i]));
        ccp[i].cfd=-1;
        ccp[i].tid=-1;
    }

    //反复遍历ccp数组找到可用的,(大家可以考虑释放资源的序号存放在堆栈或者队列中,
    //我们只要去使用其中标记为-1的资源)
    while(1){
        struct sockaddr_in clientInfo;
        socklen_t len = sizeof(clientInfo);
        int cfd=accept(lfd,(struct sockaddr*)&clientInfo,&len);//阻塞函数
        
        // 从这个数组中找到一个可以用的sockInfo元素
        struct communPara *pinfo;
        for(int i=0;i<max;++i){
            if(ccp[i].cfd==-1){
                pinfo=&ccp[i];
                break;
            }
            if(i==max-1){
                sleep(1);
                i=-1;
            }
        }

        pinfo->cfd=cfd;
        memcpy(&pinfo->clientInfo,&clientInfo,len);
        // 创建子线程
        pthread_create(&pinfo->tid, NULL, communication, pinfo);
        pthread_detach(pinfo->tid);
    }
    // for(int i=0;i<max;++i){  
    //     // if(ccp[i].tid!=-1){ //有数据证明不可用
    //     //     if(i==max-1) {
    //     //         i=-1;
    //     //         sleep(2);
    //     //     }
    //     //     continue;
    //     // }else{
    //     //     // 5.accept接受客户端连接(循环里)
    //     //     socklen_t len = sizeof(ccp[i].clientInfo);
    //     //     ccp[i].cfd=accept(lfd,(struct sockaddr*)&ccp[i].clientInfo,&len);
    //     //     if(ccp[i].cfd==-1){ perror("accept");  continue;}

    //     //     // 6.创建子线程负责通信(参数:clientInfo,cfd,tid)
    //     //     //pthread_create函数不会让主线程不阻塞,所以可以在communication中释放资源
    //     //     pthread_create(&ccp[i].tid,NULL,communication,&ccp[i]);
    //     //     pthread_detach(ccp[i].tid);
    //     }
    // }
    close(lfd);
    return 0;
}

注:纯属学习交流。如果有问题或者涉及版权请联系我:15909440083.

如果有同学想看看效果可以改一下自己的IP

// TCP通信的客户端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main() {
    char serverIP[]={"192.168.73.100"};
    unsigned short serverPort=9090;

    // 1.创建套接字
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd == -1) { perror("socket");  exit(-1);}

    // 2.连接服务器端
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    inet_pton(AF_INET, serverIP, &serveraddr.sin_addr.s_addr);
    serveraddr.sin_port = htons(serverPort);
    int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    if(ret == -1) { perror("connect"); exit(-1); }
    
    // 3. 通信
    char recvBuf[1024];
    int i = 0;
    while(1) {
        memset(recvBuf,0,sizeof(recvBuf));
        sprintf(recvBuf, "data : %d", i++);
        sleep(1);   //这个只是让程序发送的慢一些//尽量让中断(ctrl+c)发生在睡眠的时候,要不然服务器那边读数据会有问题
        
        // 给服务器端发送数据
        write(fd, recvBuf, strlen(recvBuf)+1);

        memset(recvBuf,0,sizeof(recvBuf));
        int len = read(fd, recvBuf, sizeof(recvBuf));
        if(len == -1) {
            perror("read");
            exit(-1);
            // break;
        } else if(len > 0) {
            printf("recv server : %s\n", recvBuf);
        } else if(len == 0) {
            // 表示服务器端断开连接
            printf("server closed...\n");
            break;
        }
       
    }

    // 关闭连接
    close(fd);
    return 0;
}

编译的代码也放在这

g++ gyw_server_thread.c -o gywpths -lpthread
gcc gyw_client.c -o gywc
./gywpths
./gywc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值