tcp网络编程——2

时间:2024-04-23 07:48:54

1.一个服务器只能有一个客户端连接(下面代码)

​​​​​​​tcp网络编程(基础)-****博客

2.一个服务器可以有多个客户端连接(多线程)

server端创建多个线程,每个线程与不同的client端建立连接。

-----这里只需要改变下TcpServer.hpp就行了

#pragma once

#include<iostream>
#include<pthread.h>
#include"Socket.hpp"

class TcpServer;  //在ThreadData前声明,ThreadData才可以调用TcpServer,否则TcpServer未定义
class ThreadData
{
public:
    ThreadData(Socket* s, TcpServer* t, std::string& clientip, uint16_t port)
        :sockp(s)
        ,tcp_this(t)
        ,_clientip(clientip)
        ,_port(port)
        {}
public:
    Socket* sockp;
    TcpServer* tcp_this;
    std::string _clientip;
    uint16_t _port;
};

class TcpServer
{
public:
    TcpServer(uint16_t port) :_port(port), _listensocket(new TcpSocket())
    {
        _listensocket->BuildListenSocketMethod(_port, defaultbackflag); //设置为监听状态
    }
    
    static void* Thread_Run(void* args) //根据pthread_create的要求,这个函数的参数只能是void*,并且只有一个,所以用static
    {
        pthread_detach(pthread_self()); //将线程设置为分离状态,主线程就不用阻塞等待(join)子线程
        ThreadData* td = static_cast<ThreadData*>(args);  

        char bufferin[1024];
        while(true)
        {
            ssize_t n = recv(td->sockp->GetSockfd(), bufferin, sizeof(bufferin)-1, 0); //接收client发送的信息
            //ssize_t n = (s->GetSockfd(), bufferin, sizeof(bufferin)-1);
            if(n > 0)
            {
                bufferin[n] = 0;
                std::string ret;
                ret += td->_clientip;
                ret += " ";
                ret += std::to_string(td->_port);
                std::cout << ret << " " << "client say#" << bufferin << std::endl;    
            }
            else
            {
                break;
            }
        }

        return nullptr;
    }

    void Loop()
    {
        //client的ip,port
        std::string peerip;
        uint16_t peerport;

        while(true)
        {

            Socket* s = _listensocket->AcceptConnection(&peerip, &peerport); //服务端接收客户端发来的连接请求
            if(s == nullptr) exit(0);
            std::cout << "accept success" << std::endl;
            //创建线程
            pthread_t id;
            ThreadData* td = new ThreadData(s, this, peerip, peerport); 
            pthread_create(&id, nullptr, Thread_Run, td); //我们传结构体给Thread_Run函数
            //我们不能join去回收,我们采取将子线程分离(pthread_detach)方式
            //原因:join会阻塞等待,如果有新的客户端想连接(connect)服务端,而server在join阻塞,并没有accept,导致connect失败

            // ssize_t n = recv(s->GetSockfd(), bufferin, sizeof(bufferin)-1, 0); //接收client发送的信息
            // //ssize_t n = (s->GetSockfd(), bufferin, sizeof(bufferin)-1);
            // if(n > 0)
            // {
            //     bufferin[n] = 0;
            //     std::string ret;
            //     ret += peerip;
            //     ret += " ";
            //     ret += std::to_string(peerport);
            //     std::cout << ret << " " << "client say#" << bufferin << std::endl;
            // }
            // else
            // {
            //     break;
            // }
        }
    }

    ~TcpServer()
    {
        delete _listensocket;
    }
private:
    int _port;
    Socket* _listensocket;
};