选择不指示pthread_create启动的函数中的数据到达
我编写了一个简单的多线程TCP echo服务器,用于试验线程。下面是我的主要功能的代码选择不指示pthread_create启动的函数中的数据到达,c,select,pthreads,C,Select,Pthreads,我编写了一个简单的多线程TCP echo服务器,用于试验线程。下面是我的主要功能的代码 #include "server_lib.h" #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <errno.h> int main(int argc, char *argv[]) { Server s = setup_socket(); pthread_t
#include "server_lib.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
int main(int argc, char *argv[]) {
Server s = setup_socket();
pthread_t clients[MAX_CLIENT];
int connfd, rv = 0;
client_data.client_number = 0;
for(;;) {
connfd = accept(s.sockfd, (struct sockaddr*)&s.sa, (socklen_t*)&s.addrlen);
if (connfd < 0 && errno != EAGAIN)
handle_error("accept failed");
if (connfd > 0) {
client_data.client_number++;
if (client_data.client_number <= MAX_CLIENT) {
socket_nonblocking(&connfd);
disable_nagles_algo(&connfd);
/* Send the client number to client first */
rv = send(connfd, (void *)&client_data.client_number,
sizeof(client_data.client_number), 0);
ThreadDataT *t = (ThreadDataT*)malloc(sizeof(ThreadDataT));
t->fd = connfd;
if (pthread_create(&clients[client_data.client_number-1], NULL, HandleMessage, (void*)t) != 0){
handle_error("pthread_create failed");
}
/* Lets close our copy of connfd */
}
else {
rv = send(connfd, "Max clients reached!\n", 21, 0);
client_data.client_number--;
close(connfd);
}
}
usleep(100000);
}
close(s.sockfd);
}
下面是通过pthread_create调用的HandleMessage函数的代码
void* HandleMessage(void *data) {
/* Lets detach first */
pthread_detach(pthread_self());
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
ThreadDataT *t = (ThreadDataT*)data;
fd_set testfd;
FD_ZERO(&testfd); FD_SET(t->fd, &testfd);
int rv = 0;
for (;;) {
int result = select(FD_SETSIZE, &testfd, NULL, NULL, &timeout);
if (result < 0) {
perror("select failed");
pthread_exit(&result);
}
if (result > 0) {
if(FD_ISSET(t->fd, &testfd)) {
/* We have some data */
rv = echo_content(&t->fd);
if (rv < 0) {
if (rv != -10)
perror("echo_content failed");
close(t->fd);
free(t);
pthread_exit(NULL);
}
}
}
usleep(1000);
}
return 0;
}
下面是注释中要求的echo_内容函数的代码
int echo_content(int *connfd) {
unsigned char buffer[2048];
int size = recv(*connfd, buffer, sizeof(buffer), 0);
if (size < 0)
handle_error("recv");
if (size > 0) {
if (strstr((const char*)buffer, "quit") != NULL){
printf("Closing connection with client\n");
send(*connfd, "bye\n", 4, 0);
return -10;
}
size = send(*connfd, buffer, size, 0);
} else
printf("WARNING: Failed to recieve data\n");
return size;
}
代码使用的数据结构定义如下
#ifndef __SERVER_LIB_H__
#define __SERVER_LIB_H__
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while(0)
#define PORT 50000
#define MAX_CLIENT 2
typedef struct {
int sockfd;
struct sockaddr_in sa;
int addrlen;
} Server;
typedef unsigned char ClientNumber;
typedef struct {
ClientNumber clients[MAX_CLIENT];
short client_number;
} ClientDataT;
ClientDataT client_data;;
typedef struct {
int fd;
} ThreadDataT;
Server setup_socket(void);
int echo_content(int *);
void socket_nonblocking(int *);
void disable_nagles_algo(int *);
void* HandleMessage(void*);
#endif /* __SERVER_LIB_H__ */
编译上述代码后,我可以使用telnet连接到它。我在telnet中没有看到服务器发送的客户端号码。接下来,我输入了一些信息,并期望它会回响,但这并没有发生
调试时,我注意到无论在客户端输入什么,SelectSystemCallinHandleMessage始终返回0。为了进行测试,我设置了select的writefds参数,然后select返回值>0,表示套接字需要写入。同样的代码用于fork模型。基于fork的代码是
这段代码几乎和基于fork的代码相似,所以我有点不明白它为什么不起作用。有人能告诉我我哪里做错了吗?可能还有其他问题,但请尝试将FD_集移动到循环中:
for (;;) {
FD_SET(t->fd, &testfd);
int result = select(FD_SETSIZE, &testfd, NULL, NULL, &timeout);
AFIK,选择call modify fd sets,可以从集合中删除testfd
另一个可能的问题是select调用的零超时。select的手册页显示:
如果
timeval结构为零,然后选择立即返回。这
用于轮询。如果timeout为NULL,则选择no timeout
可以无限期地阻止
您也可以尝试无限期超时:
for (;;) {
FD_SET(t->fd, &testfd);
int result = select(FD_SETSIZE, &testfd, NULL, NULL, NULL);
这样就可以删除丑陋的轮询睡眠:usleep1000 “插座不阻塞&connfd;”为什么,当您在处理clientserver套接字时?'rv=echo\u content&t->fd;'每个客户端服务器一个线程中的所有select gunge是怎么回事?嗨,Martin,非阻塞代码来自原始的遗留代码库。是的,我可以放下它。此外,我还添加了echo_内容函数的定义。代码可以不使用select,我知道,但我只是好奇为什么select不表示数据的到达。谢谢你,FD_SET是键:-。同样是的,使用0超时然后睡眠确实没有意义。我已经更新了代码,使select无限期阻塞,并放弃了睡眠。