C ++多客户端TCP服务器

时间:2015-11-25 17:33:27

标签: c++ sockets tcp

我想使用C ++制作一个使用TCP协议的服务器和客户端程序。服务器必须能够一次处理多个客户端。但问题是,例如,在启动服务器后,我运行2个客户端,其中服务器的IP地址和端口作为参数。接下来,两个客户端都将数据发送到服务器。首先,两个客户端都可以将数据发送到服务器,服务器可以读取数据。但是,一旦服务器从第二个客户端收到数据,它似乎就停止了从第一个客户端接收。你有任何解决方案吗?

这是服务器代码

# >> Running each test 2048 times. Test will take about 1 second.
# >> _each_with_object is similar to _inject
# >> _inject is faster than _zip by 19.999999999999996% ± 10.0%
# >> _zip is faster than _map by 10.000000000000009% ± 10.0%
# >> 
# >> Running each test 2048 times. Test will take about 1 second.
# >> _each_with_object is similar to _inject
# >> _inject is similar to _zip
# >> _zip is similar to _map
# >> 
# >> Running each test 2048 times. Test will take about 1 second.
# >> _inject is similar to _each_with_object
# >> _each_with_object is similar to _zip
# >> _zip is faster than _map by 10.000000000000009% ± 10.0%
# >> 
# >> Running each test 2048 times. Test will take about 1 second.
# >> _each_with_object is similar to _inject
# >> _inject is faster than _zip by 19.999999999999996% ± 10.0%
# >> _zip is faster than _map by 10.000000000000009% ± 10.0%
# >> 
# >> Running each test 2048 times. Test will take about 1 second.
# >> _each_with_object is similar to _inject
# >> _inject is faster than _zip by 19.999999999999996% ± 10.0%
# >> _zip is faster than _map by 10.000000000000009% ± 10.0%
# >> 

客户端代码

using namespace std;

void *task1(void *);

static int connFd;
void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char* argv[])
{
    int pId, portNo, listenFd;
    socklen_t len; //store size of the address
    bool loop = false;
struct sockaddr_in svrAdd, clntAdd;

pthread_t threadA[3];

if (argc < 2)
{
    cerr << "Syntam : ./server <port>" << endl;
    return 0;
}

portNo = atoi(argv[1]);

if((portNo > 65535) || (portNo < 2000))
{
    cerr << "Please enter a port number between 2000 - 65535" << endl;
    return 0;
}

//create socket
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(listenFd < 0)
{
    cerr << "Cannot open socket" << endl;
    return 0;
}

bzero((char*) &svrAdd, sizeof(svrAdd));

svrAdd.sin_family = AF_INET;
svrAdd.sin_addr.s_addr = INADDR_ANY;
svrAdd.sin_port = htons(portNo);

//bind socket
if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0)
{
    cerr << "Cannot bind" << endl;
    return 0;
}

    listen(listenFd, 5);

    int noThread = 0;

    while (noThread < 3)
    {
        socklen_t len = sizeof(clntAdd);
        cout << "Listening" << endl;

    //this is where client connects. svr will hang in this mode until           client conn
        connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len);

        if (connFd < 0)
        {
            cerr << "Cannot accept connection" << endl;
            return 0;
        }
        else   
        {
            cout << "Connection successful" << endl;
        }

        pthread_create(&threadA[noThread], NULL, task1, NULL); 

        noThread++;
    }

    for(int i = 0; i < 3; i++)
    {
        pthread_join(threadA[i], NULL);
    }  
}

void *task1 (void *dummyPt)
{
    cout << "Thread No: " << pthread_self() << endl;
    char test[256];
    bzero(test, 256);
    bool loop = false;
    while(!loop)
    {       
        bzero(test, 256);     
        int n = read(connFd, test, 255);
        if (n < 0) error("ERROR reading from socket");
        printf("Here is the message: %s\n",test);            
    }
    cout << "\nClosing thread and conn" << endl;
    close(connFd);
}

1 个答案:

答案 0 :(得分:4)

Yor connFd是一个全局变量,您可以从主线程和所有处理线程访问它。这不行!想象一下 - 您已经接受了第一个连接并将变量设置为接收套接字。你已经产生了开始阅读的处理线程。接下来你知道,另一个连接即将到来,你也会收到它!这一刻connFd指向新连接,因此已经使用它的线程将突然切换到新连接!当然不好。

解决此问题的方法是以不跨线程共享的方式将连接传递给线程。最简单的方法是使用C ++线程类。

例如,这是说明上述想法的代码片段:

void handle_connection(int fd) {
   ... <your task1 code>
}

... 
std::vector<std::thread> threads;
...
int conn = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
threads.push_back(std::thread(&handle_connection, conn));
...

... (in the end)
for (auto&& t : threads)
    t.join();