前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多线程服务器

多线程服务器

原创
作者头像
买唯送忧
修改2021-09-13 11:12:00
5810
修改2021-09-13 11:12:00
举报
文章被收录于专栏:虚拟技术学习

一、思路

1、阻塞监听之前

(1)、socket函数

socket(AF_INET, SOCK_STREAM, 0)socket函数是为了创建服务器端的套接字,是用来监听是否有客户端来连接的;

(2)、setsockopt函数

setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)setsockopt是为了设置端口复用,opt设置为1;

(3)、bind函数

bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)bind函数是为了将服务端的地址结构(IP+端口)绑定到套接字上;

(4)、listen函数

listen(lfd, 128)listen函数是为了设置监听上限的,不是阻塞监听;

2、监听阻塞之后

在接收到客户端的请求之后,需要分配主线程和子线程的工作:

主线程:将子线程分离出进程,使其不会影响后续的接收,子线程结束后,自行回收结束

子线程:使用读写的套接字与客户端进行通信

(1)、accept函数

cfd = accept(lfd,(struct sockaddr*)&cli_addr, &cli_addr_len)accept函数阻塞监听客户端的连接,如果监听到连接之后就会得到客户端的地址结构和与该客户端通信的套接字。

(2)、pthread_create函数

pthread_create(tid, NULL, do_work, (void *)&cfd)pthread_create函数创建子线程并去执行子线程对应的回调函数;

(3)、主线程中分离子线程

(4)、子线程中进行通信


pthread_server.h代码如下:

代码语言:c++
复制
#ifndef __PTHREAD_SERVER_H_
#define __PTHREAD_SERVER_H_

#include<iostream>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<strings.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
using namespace std;

class PthreadTcp{
public:
    PthreadTcp(string note){
        cout << note << endl;
    }

    int Socket(int domain, int type, int protocol){
        int lfd = socket(domain, type, protocol);
        if (lfd == -1){
            cout << "socket() fail: " << strerror(errno) << endl;
            exit(1);
        }
        return lfd;
    }

    void setAddr(struct sockaddr_in& ser_addr, int flg){
        bzero(&ser_addr, sizeof(ser_addr));
        ser_addr.sin_family = AF_INET;
        ser_addr.sin_port = htons(8888);
        if (flg == 1)
            ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        else
            inet_pton(AF_INET, "127.0.0.1", &ser_addr.sin_addr.s_addr);
    }

    void setSockOpt(int lfd){
        int opt = 1;
        int ret = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        if (ret == -1){
            cout << "setsockopt() fail:" << strerror(errno) << endl;
        }
    }

    void Bind(int lfd, const struct sockaddr* ser_addr, socklen_t ser_len){
        int ret = bind(lfd, ser_addr, ser_len);
        if (ret == -1){
            cout << "bind() fail :" << strerror(errno) << endl;
            exit(1);
        }
    }

    void Listen(int lfd, int backlog){
        int ret = listen(lfd, backlog);
        if (ret == -1){
            cout << "listen() fail :" << strerror(errno) << endl;
            exit(1);
        }
    }

    int Accept(int lfd, struct sockaddr* cli_addr, socklen_t* cli_len){
        int cfd;
        do{
            cfd = accept(lfd, cli_addr, cli_len);
            if (cfd == -1){
                if (errno == EINTR)
                    continue;
                else {
                    cout << "accept() --- error: " << strerror(errno) << endl;
                    exit(0);
                }
            }


        }while(0);
        
        return cfd;
    }

    int Connect(int cfd, const struct sockaddr *addr, socklen_t addrlen){
        int ret = connect(cfd, addr, addrlen);
        if (ret == -1){
            cout << "connect() fail: " << strerror(errno) << endl;
            exit(1);
        }
        return ret;
    }

    int Read(int fd, void *buf, size_t count){
        int ret = read(fd, buf, count);
        if (ret == 0){
            close(fd);
            cout << "the client close connection!!!" << endl;
            exit(0);
        } else if (ret == EAGAIN){
            cout << "the error is EAGAIN" << endl;
            exit(1);
        } else if (ret > 0){
            return ret;
        }
        return ret;
    }

    int Write(int fd, const void *buf, size_t count){
        int ret = write(fd, buf, count);
        return ret;
    }
};


#endif

pthread_server.cpp代码如下:

代码语言:c++
复制
#include "pthread_server.h"
#include<ctype.h>

PthreadTcp *tcp ;

void* do_work(void* arg){
    int ret, n, cfd;
    char buf[BUFSIZ];
    cfd = *((int*)arg);
    while((n = tcp->Read(cfd, buf, sizeof(buf))) != -1){
        if (n == 0){
            close(cfd);
            pthread_exit(NULL);
        }
        for (int i = 0; i < n; i ++){
            buf[i] = toupper(buf[i]);
        }
        tcp->Write(cfd, buf, n);
        tcp->Write(STDOUT_FILENO, buf, n);
    }
}

int main()
{

    int cfd;
    pthread_t tid;
    struct sockaddr_in serv_addr, cli_addr;
    socklen_t cli_addr_len = sizeof(cli_addr);
    tcp = new PthreadTcp("server working\n");
    int lfd = tcp->Socket(AF_INET, SOCK_STREAM, 0); //创建服务器端套接字
    tcp->setSockOpt(lfd); //设置端口复用
    tcp->setAddr(serv_addr, 1); //设置服务器端地址结构
    tcp->Bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); //绑定地址结构
    tcp->Listen(lfd, 128);

    cout << "server start receive client's message" << endl;

    while(1){
        cfd = tcp->Accept(lfd, (struct sockaddr*)&cli_addr, &cli_addr_len);
        pthread_create(&tid, NULL, do_work, (void *)&cfd);
        pthread_detach(tid);
    }
    

    return 0;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、思路
    • 1、阻塞监听之前
      • (1)、socket函数
      • (2)、setsockopt函数
      • (3)、bind函数
      • (4)、listen函数
    • 2、监听阻塞之后
      • (1)、accept函数
      • (2)、pthread_create函数
      • (3)、主线程中分离子线程
      • (4)、子线程中进行通信
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档