服务器多线程无法保存最后一个套接字描述符

时间:2015-12-30 16:11:40

标签: c++ multithreading server client

我有一个项目,我们正在使用线程。 问题是,每次特定客户端发送消息时,它只保存已建立的LAST client_sock,这样我就无法保存前一个线程的调用,因为我从任何客户端发送的每条消息都回答了我最后一个消息创建的客户端意味着以前的客户端已经运行。

class ServerTcp {
private:
pthread_t threads[50];

这是创建线程的函数,它发送到recieveAndSend:

void ServerTcp:: acceptTheReaquest(){
struct sockaddr_in client_sin;
unsigned int addr_len = sizeof(client_sin);
int sockFd;
while((sockFd = accept(this->sock,  (struct sockaddr *) &client_sin,  
&addr_len)) >= 0){
     struct arg_struct args; //has only 2 values, initialized in next lines
     args.client_sock = sockFd;
     args.server = this;
     cout << "created " << sockFd << endl;
    pthread_create(&threads[numOfThreads],NULL,
    &ServerTcp::recieveAndSend, &args);
    numOfThreads++;
}
}

这是函数receiveAndSend:

static void* ServerTcp:: recieveAndSend(void * args){
arg_struct* arguments = static_cast<arg_struct*>(args);
char buffer[4096];
while (true){
    memset(&buffer, 0, sizeof(buffer));
    int bytes = arguments->server->recieveFromClient(buffer,
     arguments->client_sock);
    if (bytes >0){
        string message = arguments->server->reciveOutput(buffer);
        arguments->server->sendTO(message, arguments->client_sock);
    }
}
return (void*)NULL;
}

这是函数sendTo:

void ServerTcp:: sendTO(string answer, int client_sock){
cout << "sending to " << client_sock << endl;
char buffer[4096];
strcpy(buffer, answer.c_str());
this->sent_bytes = send(client_sock, buffer, sizeof(buffer), 0);
}

输出:

created 4
received from 4
created 5
received from 5

这意味着我已经为client_sock 4创建了一个线程,并等待从client_sock 4接收,同样对于client_sock 5.现在我希望服务器打印发送到4,从4接收 - 因为我使用了客户端client_sock 4是第一个创建的,也是我发送消息的,但它仍然保存client_sock 5,输出为:

sending to 5
received from 5

而不是

sending to 4
received from 4

..... HELP ??

1 个答案:

答案 0 :(得分:1)

您的代码中的错误如下(我删除了不相关的代码行,并清理了缩进):

while((sockFd = accept(this->sock,  (struct sockaddr *) &client_sin, &addr_len)) >= 0)
{
     struct arg_struct args;
     args.client_sock = sockFd;
     args.server = this;

     pthread_create(&threads[numOfThreads],NULL,
                    &ServerTcp::recieveAndSend, &args);
     numOfThreads++;
}

您正在堆栈中的本地作用域中实例化arg_struct。然后,您将指向arg_struct的指针传递给新线程。

这里的问题是,在父线程中返回pthread_create()之后,循环终止(好,循环的当前迭代终止,并且它再次启动),arg_struct不再有效。

但是,子线程将尝试通过从pthread_create()接收的指针独立访问它,这将导致未定义的行为。

您观察到的行为是这种未定义行为的结果(父线程将在第二个线程的同一个原始内存位置实例化堆栈上的新arg_struct,但第一个线程在醒来时仍然会在同一位置查看。)

您需要做的是使用arg_struct运算符在堆上构造new。这样,对于新线程,实例化的arg_struct将继续存在。当然,新线程负责delete arg_struct,当它完成时,以避免泄漏内存。