网络编程之——多线程并发服务器

思路:循环等待连接,连接成功后创建一个子线程处理该连接的数据通信,然后主线程继续等待连接。
socket接口封装:

#include "wrap.h"
#include 
#include 
#include 

void sys_err(const char *ch)
{
     
    perror(ch);
    exit(1);
}

int Socket(int domain, int type, int protocol)
{
     
    //创建socket
    int ret = socket(domain,type,protocol);
    if(ret == -1)
    {
     
        sys_err("socket error");
    }

    return ret;
}

int Setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen)
{
     
    int ret = setsockopt(sockfd,level,optname,optval,optlen);
    if(ret == -1)
    {
     
        sys_err("setsockopt error");
    }

    return ret;
}

int Bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
     
    //绑定ip地址和端口
    int ret = bind(sockfd,addr,addrlen);
    if(ret == -1)
    {
     
        sys_err("socket bind error");
    }

    return ret;
}

int Listen(int sockfd, int backlog)
{
     
    //设置监听上限值
    int ret = listen(sockfd,backlog);
    if(ret == -1)
    {
     
        sys_err("socket listen  error");
     }

     return ret;
}

int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
     
    int fdc = 0;
again:
    //监听客户端连接
    fdc = accept(sockfd,addr,addrlen);
    if (fdc == -1)
    {
     
        if (errno == ECONNABORTED || errno == EINTR)
        {
     
            goto again;
        }else
        {
     
            sys_err("socket accept error");
        }
    }

    return fdc;
}

int Connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
     
    int ret = 0;

    ret = connect(sockfd,addr,addrlen);
    if(ret == -1)
    {
     
        sys_err("connect error");     
    }

    return ret;
}

int Close(int fd)
{
     
    int ret = close(fd);
    if(ret == -1)
    {
     
        sys_err("close error");
     }

    return ret;
}

服务器端代码:

#include "wrap.h"
#include 
#include 
#include 
#include  //toupper
#include 
#include //inet_ntop
#include //bzero

#define PORT 8888
struct fdc_info
{
     
    struct sockaddr_in addr;
    int fdc;
};

void* dowork(void *arg)//线程函数
{
     
    struct fdc_info*  info = (struct fdc_info*)arg;
    char clit_ip[1024];
    char buf[BUFSIZ];
    bzero(buf,sizeof(char)*BUFSIZ);

    printf("client ip:%s,port:%d\n",
    inet_ntop(AF_INET,&info->addr.sin_addr.s_addr,clit_ip,1024),
    ntohs(info->addr.sin_port));
    while(1)
    {
     
        int ret = read(info->fdc,buf,sizeof(buf));
        if(ret == 0)
        {
     
            printf("client %d exit...\n",ntohs(info->addr.sin_port));
            break;
        }

        write(STDOUT_FILENO,buf,ret);
        for(int i=0;i<ret;++i)
        {
     
            buf[i] = toupper(buf[i]);
        }

        write(info->fdc,buf,ret);
    }

    Close(info->fdc);

    return (void*)0;//pthread_exit();
}

void server_thread()
{
     
    int fds = 0;
    //int fdc = 0;
    struct sockaddr_in serv_addr,clit_addr;
    socklen_t clit_addr_len;
    struct fdc_info fdis[256];
    
    bzero(&serv_addr,sizeof(serv_addr));
    bzero(&clit_addr,sizeof(clit_addr));
    bzero(&fds,sizeof(struct fdc_info)*256);
    clit_addr_len = sizeof(clit_addr);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);


    fds = Socket(AF_INET,SOCK_STREAM,0);
    
	int opt = 1;//设置端口复用
    Setsockopt(fds,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(opt));

    Bind(fds,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
    Listen(fds,128);

    int i = 0;
    while (i<256)
    {
     
        int fdc = Accept(fds,(struct sockaddr*)&clit_addr,&clit_addr_len);

        fdis[i].addr = clit_addr;
        fdis[i].fdc = fdc;
        pthread_t pd;
        pthread_create(&pd,NULL,dowork,&fdis[i]);
        pthread_detach(pd);//分离线程
        ++i;
    }

    Close(fds);
}

int main(int args,char *argc[])
{
     
    server_thread();

    return 0;
}

测试:
可以开启多个终端使用nc 127.0.0.1 8888命令创建连接进行测试

你可能感兴趣的:(Linux,网络编程,C/C++,socket,多线程,c++,网络)