栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Linux c 多线程并发服务器

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux c 多线程并发服务器

文章目录
  • 1、流程
  • 2、代码
  • 3、socket常用函数出错处理封装

1、流程
全局定义了一个结构体,成员为,客户端通信的文件描述符,和返回的客户端信息结构体

主线程:
	创建结构体数组(存文件描述符、客户端信息结构体)
	1、socket创建套接字
	2、bind绑定ip端口号
	3、listen 设置最大连接数
	4、accpet阻塞等待客户端连接
		连接成功之后间:用于通信的文件描述符存到结构体中
	5、创建子线程,并把对应的结构体数组传递过去
	6、设置线程分离(自动回收)

子线程:
	1、read数据
	2、将读到的数据转换成大写
	3、回写给客户端
	循环监听,知道read读到0表示客户端断开
2、代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "socket_wrap.h"

#define MAXLINE 8192
#define SERV_PORT 9999

struct s_info {                     //定义一个结构体, 将地址结构跟cfd捆绑
    struct sockaddr_in cliaddr;
    int connfd;
};

void *do_work(void *arg)
{
    int n,i;
    struct s_info *ts = (struct s_info*)arg;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];      //#define INET_ADDRSTRLEN 16  可用"[+d"查看

    while (1) {
        n = Read(ts->connfd, buf, MAXLINE);                     //读客户端
        if (n == 0) {
            printf("the client %d closed...n", ts->connfd);
            break;                                              //跳出循环,关闭cfd
        }
        printf("received from %s at PORT %dn",
                inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
                ntohs((*ts).cliaddr.sin_port));                 //打印客户端信息(IP/PORT)

        for (i = 0; i < n; i++) 
            buf[i] = toupper(buf[i]);                           //小写-->大写

        Write(STDOUT_FILENO, buf, n);                           //写出至屏幕
        Write(ts->connfd, buf, n);                              //回写给客户端
    }
    Close(ts->connfd);

    return (void *)0;
}

int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    pthread_t tid;

    struct s_info ts[256];      //创建结构体数组.
    int i = 0;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);                     //创建一个socket, 得到lfd

    bzero(&servaddr, sizeof(servaddr));                             //地址结构清零
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);                               //指定本地任意IP
    servaddr.sin_port = htons(SERV_PORT);                                       //指定端口号 

    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));             //绑定

    Listen(listenfd, 128);                                                      //设置同一时刻链接服务器上限数

    printf("Accepting client connect ...n");

    while (1) {
        cliaddr_len = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);   //阻塞监听客户端链接请求
        ts[i].cliaddr = cliaddr;
        ts[i].connfd = connfd;

        pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
        pthread_detach(tid);                                                    //子线程分离,防止僵线程产生.
        i++;
    }

    return 0;
}


3、socket常用函数出错处理封装

socket_wrap.h

#ifndef __WRAP_H_
#define __WRAP_H_

void perr_exit(const char* s);
int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr);
int Bind(int fd,const struct sockaddr* sa,socklen_t salen);
int Connect(int fd,const struct sockaddr* sa,socklen_t salen);
int Listen(int fd,int backlog);
int Socket(int family,int type,int protocol);
ssize_t Read(int fd,void* ptr,size_t nbytes);
ssize_t Write(int fd,const void* ptr,size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd,void* vptr,size_t n);
ssize_t Writen(int fd,const void* vptr,size_t n);
static ssize_t my_read(int fd,char* ptr);
ssize_t Readline(int fd,void* vptr,size_t maxlen);

#endif // !__WRAP_H_

socket_wrap.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "socket_wrap.h"

void perr_exit(const char* s)
{
    perror(s);
    exit(1);
}

int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr)
{
    int n;
again:
    if((n=accept(fd,sa,salenptr))<0)
    {
        if(errno == EConNABORTED || (errno==EINTR))
            goto again;
        else
            perr_exit("accept error");
    }
    return n;
}

int Bind(int fd,const struct sockaddr* sa,socklen_t salen)
{
    int n;
    if((n=bind(fd,sa,salen))<0)
    {
        perr_exit("bind error");
    }
    return n;
}

int Connect(int fd,const struct sockaddr* sa,socklen_t salen)
{
    int n;
    if((n=connect(fd,sa,salen))<0)
        perr_exit("connect error");
    return n;

}

int Listen(int fd,int backlog)
{
    int n;
    if((n=listen(fd,n))<0)
    {
        perr_exit("listen error");
    }
    return n;
}


int Socket(int family,int type,int protocol)
{
    int n;
    if((n=socket(family,type,protocol))<0)
        perr_exit("socket error");
    return n;
}

ssize_t Read(int fd,void* ptr,size_t nbytes)
{
    ssize_t n;
again:
    if((n=read(fd,ptr,nbytes))<0)
    {
        if(errno==EINTR)
            goto again;
        else
            return -1;
    }
    return n;
}

ssize_t Write(int fd,const void* ptr,size_t nbytes)
{
    ssize_t n;
    if((n=write(fd,ptr,nbytes))<0)
        perr_exit("write error");
    return n;
}

int Close(int fd)
{
    int n;
    if((n=close(fd))<0)
        perr_exit("close error");
    return n;
}

ssize_t Readn(int fd,void* vptr,size_t n)
{
    size_t nleft;   // unsigned int 剩余未读取字节数
    ssize_t nread; // int 实际读到的字节数
    char* ptr;
    ptr = vptr;
    nleft = n;
    while (nleft>0)
    {
        if((nread = read(fd,ptr,nleft))<0)
        {
            if(errno == EINTR)        
                nread = 0;
            else
             return -1;
        }
        else if(nread == 0)
            break;
        nleft -= nread;
        ptr+=nread;
    }
    return n-nread;
    
}

ssize_t Writen(int fd,const void* vptr,size_t n)
{
    size_t nleft;
    ssize_t nwritten;
    const char* ptr;
    ptr = vptr;
    nleft = n;
    while(nleft>0)
    {
        if((nwritten=write(fd,ptr,nleft))<=0)
        {
            if(nwritten<0 && errno==EINTR)
                nwritten = 0;
            else
                return -1;
        }
        nleft -= nwritten;
        ptr += nwritten;
    }
    return n;
}

static ssize_t my_read(int fd,char* ptr)
{
    static int read_cnt;
    static char* read_ptr;
    static char read_buf[100];
    if(read_cnt<=0)
    {
    again:
        if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0)
        {
            if(errno == EINTR)
                goto again;
            return -1;
        }
        else if(read_cnt == 0)
            return 0;
        read_ptr = read_buf;
    }
    read_cnt--;
    *ptr = *read_ptr++;
    return 1;
}

// 传出参数 vptr
ssize_t Readline(int fd,void* vptr,size_t maxlen)
{
    ssize_t n,rc;
    char c,*ptr;
    ptr = vptr;
    for(n=1;n
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/457606.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号