linux上的socket通讯(二)多线程方案

一、框架方案

accept是主线程,不断等待客户端的连接,一旦有客户端连接过来,那么创建新的线程用于通讯

 

注意资源共享:栈空间不共享,全局区和堆空间是共享的;

二、多线程的并发实现

1.主进程

(1)server建立的步骤中,accept连接之后,需要创建一个新的子线程用于处理当前连接的客户端,将通讯、接受消息等放置到子线程中处理;

(2)accept建立的连接,得到了客户端的地址信息以及socket的文件描述符,这些都需要作为参数传递给子进程,因此建立一个结构体并声明一个结构体变量用于存放这些结果;

//information struct
struct sockInfo
{
    struct sockaddr_in addr;//address info
    int fd;//file description
};

struct sockInfo infos[512];

void OpenSocketServer(){
    //1.socket-listener...
    //2.bind...
    //3.listen...

    //初始化结构体
    int max=(sizeof(infos)/sizeof(infos[0]));
    for (size_t i = 0; i < max; i++)
    {
        bzero(&infos[i],sizeof(infos[i]));
        infos[i].fd=-1;
    }
    //等待接受客户端的连接
    while(1){
        //从结构体数据中寻找到一个空闲的元素
        struct sockInfo* pInfo;
        for (size_t i = 0; i < max; i++)
        {
            if(infos[i].fd==-1){
                pInfo=&infos[i];
                break;
            }
        }
        //pinfo
        socklen_t sock_len=sizeof(sockaddr_in);
        int client=accept(listener,(struct sockaddr*)&pInfo->addr,&sock_len);
        if(client==-1){
            perror("accept error");
            break;
        }
        pInfo->fd=client;
        //创建子线程
        pthread_t tid;
        pthread_create(&tid,NULL,working,pInfo);
        pthread_detach(tid);//子线程有可能随着连接终止而会终止,但是不能影响主线程的正常运行,因此在这里将主线程与子线程分离
    }
    close(listener);
}

 

2.子线程

void* working(void* arg){
    //参数中得到对应的结构体
    struct sockInfo* ppinfo=(struct sockInfo*)arg;
    //打印出客户端的信息
    char ip[32];
    printf("client ip:%s,port:%d\n",
            inet_ntop(AF_INET,&ppinfo->addr.sin_addr.s_addr,ip,sizeof(ip)),
            ntohs(ppinfo->addr.sin_port));
    while(1){
        //接受数据
        char buf[1024];
        int len=recv(ppinfo->fd,buf,sizeof(buf),0);
        if(len>0){
            char buf[]="hello,i am server";
            send(ppinfo->fd,buf,sizeof(buf),0);
        }
        else if(len==0){
            printf("client disconnect\n");
            break;
        }
        else{
            perror("receive error");
            break;
        }
    }
    close(ppinfo->fd);
    ppinfo->fd=-1;//关闭的时候需要将文件描述符置为-1,作为空区可以为下次使用;
    return NULL;
}

 

 3.运行效果

注意:gcc编译的时候需要指明多线程,否则编译不通过

gcc -pthread netServer.cpp src/socketServer.cpp src/commonServer.cpp -Iinclude -o net

 

服务器与三个客户端建立了连接

 

posted on 2021-09-18 17:15  freden  阅读(457)  评论(0编辑  收藏  举报