pthread_join 处理多个客户端时分叉 TCP 服务器失败
pthread_join fails in forking TCP server when handling multiple clients
我必须创建一个多线程 TCP/IP 服务器,其中包含一个变量来计算连接的客户端数量(以及断开连接的客户端数量),并在客户端连接到服务器时打印连接的客户端数量。
这是我的client.c文件:
#define PORT 4444
int main ()
{
int clientSocket;
struct sockaddr_in serverAddress;
char buffer[1024];
ssize_t nread;
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
printf("[+]Client socket has been created\n");
memset(&serverAddress, '[=11=]', sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
perror("Errore con la connessione\n");
exit(-1);
}
while (1) {
printf("> ");
fflush(stdin);
scanf("%s", buffer);
if (nread != -1)
buffer[nread] = '[=11=]';*/
if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
perror("Errore con l'invio");
exit(1);
}
if(strcmp(buffer, ":exit") == 0) {
close(clientSocket);
printf("[-]Disconnected from Server\n");
exit(0);
}
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '[=11=]';
printf("Server received: %s\n", buffer);
}
}
close(clientSocket);
return 0;
}
这是我的 server.c 文件:
#define PORT 4444
#define MAX_CONNESSIONI 100
typedef struct myStruct {
int clientCollegati;
int clientCheSiSonoScollegati;
pthread_mutex_t mutex; // Creazione del mutex per sincronizzare la struttura
} myStruct;
myStruct *test;
myStruct *initStruct();
void *incrementa(void*);
int main ()
{
int serverSocket, bindStatus;
struct sockaddr_in serverAddress;
int clientSocket;
struct sockaddr_in newAddress;
char buffer[1024];
pid_t child;
socklen_t addrSize;
ssize_t nread;
pthread_t tid;
test = initStruct();
if (pthread_create(&tid, NULL, incrementa, NULL) != 0) {
perror("Errore nella creazione del thread t1\n");
exit(1);
}
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
memset(&serverAddress, '[=12=]', sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
bindStatus = bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
if (bindStatus == -1) {
perror("[-]Errore durante il binding\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
if (listen(serverSocket, MAX_CONNESSIONI) != -1) {
printf("Listening . . .\n\n");
}
else {
perror("[-]Error during listening\n");
exit(1);
}
while (1) {
clientSocket = accept(serverSocket, (struct sockaddr*)&newAddress, &addrSize);
if (clientSocket == -1) {
exit(-1);
}
printf("%s:%d joined\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
if (pthread_join(tid, NULL)) { // returns 3
perror("pthread_join error\n");
exit(1);
}
printf("There is/are %d client(s) connected\n", test->clientCollegati);
child = fork();
if (child == 0) {
close(serverSocket);
while (1) {
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '[=12=]';
}
if (strcmp(buffer, ":exit") == 0) {
printf("%s:%d left\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
break;
}
else {
printf("%s:%d wrote: %s\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port), buffer);
send(clientSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(clientSocket);
return 0;
}
myStruct *initStruct()
{
struct myStruct *ptr = malloc(sizeof(myStruct));
ptr->clientCollegati = 0;
ptr->clientCheSiSonoScollegati = 0;
pthread_mutex_init(&ptr->mutex, NULL); // inizializzazione dinamica del mutex
return ptr;
}
void *incrementa(void *ptr)
{
pthread_mutex_lock(&test->mutex);
test->clientCollegati++;
pthread_mutex_unlock(&test->mutex);
pthread_exit(0);
}
不幸的是,这似乎无法正常工作,你可以看到 server output and here client1 and here client2 output
- 哪里错了?我想问题是当 tid 完成并且对
pthread_join
的第二次调用被调用到一个不存在的线程(因为只有一个线程)
你的代码逻辑错误。您正在执行单个 pthread_create()
,然后执行多个 pthread_join()
。如果你想为每个连接的客户端增加值,你必须在每个成功 accept()
之后执行一个 pthread_create()
,然后是一个 pthread_join()
。注意:所有这一切都必须发生在 在 调用 fork()
之前。
Where's the mistake? I suppose that the problem is when tid
finish and a second call to that pthread_join
is invoked to a non-existent thread (because there is a single thread)
事实就是如此。在您当前的程序中,第一个 pthread_join()
成功,并且任何后续调用都失败并返回错误号 3(没有这样的进程),因为该线程不再存在。所以你已经想通了。为什么你创建一个线程,但如果你知道这是错误的,却多次加入它?
你程序的编写方式(递增后分叉)也意味着根本没有理由使用线程来递增,你甚至不需要互斥体,因为只有一个线程将在任何给定时间访问该值。换句话说,您的服务器根本不是多线程的。如果你只是想把它作为一个实验来做,那没关系,但它没有多大意义。
您可能想要做的(拥有一个多线程服务器)是每个客户端一个线程而不是每次都分叉,客户端代码在线程函数中(在那种情况下,有一个互斥体是有意义的)。请注意,这对于大量客户端而言并不能很好地扩展(一般来说,经典的 fork()
方法更好,在这种情况下你真的不需要任何线程)。
我必须创建一个多线程 TCP/IP 服务器,其中包含一个变量来计算连接的客户端数量(以及断开连接的客户端数量),并在客户端连接到服务器时打印连接的客户端数量。
这是我的client.c文件:
#define PORT 4444
int main ()
{
int clientSocket;
struct sockaddr_in serverAddress;
char buffer[1024];
ssize_t nread;
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
printf("[+]Client socket has been created\n");
memset(&serverAddress, '[=11=]', sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
perror("Errore con la connessione\n");
exit(-1);
}
while (1) {
printf("> ");
fflush(stdin);
scanf("%s", buffer);
if (nread != -1)
buffer[nread] = '[=11=]';*/
if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
perror("Errore con l'invio");
exit(1);
}
if(strcmp(buffer, ":exit") == 0) {
close(clientSocket);
printf("[-]Disconnected from Server\n");
exit(0);
}
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '[=11=]';
printf("Server received: %s\n", buffer);
}
}
close(clientSocket);
return 0;
}
这是我的 server.c 文件:
#define PORT 4444
#define MAX_CONNESSIONI 100
typedef struct myStruct {
int clientCollegati;
int clientCheSiSonoScollegati;
pthread_mutex_t mutex; // Creazione del mutex per sincronizzare la struttura
} myStruct;
myStruct *test;
myStruct *initStruct();
void *incrementa(void*);
int main ()
{
int serverSocket, bindStatus;
struct sockaddr_in serverAddress;
int clientSocket;
struct sockaddr_in newAddress;
char buffer[1024];
pid_t child;
socklen_t addrSize;
ssize_t nread;
pthread_t tid;
test = initStruct();
if (pthread_create(&tid, NULL, incrementa, NULL) != 0) {
perror("Errore nella creazione del thread t1\n");
exit(1);
}
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
memset(&serverAddress, '[=12=]', sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
bindStatus = bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
if (bindStatus == -1) {
perror("[-]Errore durante il binding\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
if (listen(serverSocket, MAX_CONNESSIONI) != -1) {
printf("Listening . . .\n\n");
}
else {
perror("[-]Error during listening\n");
exit(1);
}
while (1) {
clientSocket = accept(serverSocket, (struct sockaddr*)&newAddress, &addrSize);
if (clientSocket == -1) {
exit(-1);
}
printf("%s:%d joined\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
if (pthread_join(tid, NULL)) { // returns 3
perror("pthread_join error\n");
exit(1);
}
printf("There is/are %d client(s) connected\n", test->clientCollegati);
child = fork();
if (child == 0) {
close(serverSocket);
while (1) {
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '[=12=]';
}
if (strcmp(buffer, ":exit") == 0) {
printf("%s:%d left\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
break;
}
else {
printf("%s:%d wrote: %s\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port), buffer);
send(clientSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(clientSocket);
return 0;
}
myStruct *initStruct()
{
struct myStruct *ptr = malloc(sizeof(myStruct));
ptr->clientCollegati = 0;
ptr->clientCheSiSonoScollegati = 0;
pthread_mutex_init(&ptr->mutex, NULL); // inizializzazione dinamica del mutex
return ptr;
}
void *incrementa(void *ptr)
{
pthread_mutex_lock(&test->mutex);
test->clientCollegati++;
pthread_mutex_unlock(&test->mutex);
pthread_exit(0);
}
不幸的是,这似乎无法正常工作,你可以看到 server output and here client1 and here client2 output
- 哪里错了?我想问题是当 tid 完成并且对
pthread_join
的第二次调用被调用到一个不存在的线程(因为只有一个线程)
你的代码逻辑错误。您正在执行单个 pthread_create()
,然后执行多个 pthread_join()
。如果你想为每个连接的客户端增加值,你必须在每个成功 accept()
之后执行一个 pthread_create()
,然后是一个 pthread_join()
。注意:所有这一切都必须发生在 在 调用 fork()
之前。
Where's the mistake? I suppose that the problem is when
tid
finish and a second call to thatpthread_join
is invoked to a non-existent thread (because there is a single thread)
事实就是如此。在您当前的程序中,第一个 pthread_join()
成功,并且任何后续调用都失败并返回错误号 3(没有这样的进程),因为该线程不再存在。所以你已经想通了。为什么你创建一个线程,但如果你知道这是错误的,却多次加入它?
你程序的编写方式(递增后分叉)也意味着根本没有理由使用线程来递增,你甚至不需要互斥体,因为只有一个线程将在任何给定时间访问该值。换句话说,您的服务器根本不是多线程的。如果你只是想把它作为一个实验来做,那没关系,但它没有多大意义。
您可能想要做的(拥有一个多线程服务器)是每个客户端一个线程而不是每次都分叉,客户端代码在线程函数中(在那种情况下,有一个互斥体是有意义的)。请注意,这对于大量客户端而言并不能很好地扩展(一般来说,经典的 fork()
方法更好,在这种情况下你真的不需要任何线程)。