【发布时间】:2018-08-23 10:25:07
【问题描述】:
对于一个基准测试任务,我正在创建多个具有相同套接字描述符的服务器工作者和具有不同连接的客户端工作者。
尽管客户端线程正在为每个线程发送相同消息的副本。服务器显示它只收到每条消息的一个副本,而不是所有副本,由所有客户端线程发送。
对于 4 个线程和 2 条消息 {0,1} ,客户端输出
client 3Wrote 0
client 1Wrote 1
client 0Wrote 0
client 1Wrote 0
client 2Wrote 0
client 3Wrote 1
client 2Wrote 1
作为服务器输出的位置
Server 0 Received - 0
Server 2 Received - 1
为什么没有显示其余的消息?或者他们从未真正由客户发送?
void *clientWorker(void *threadarg) {
struct workDetails *thisWork;
thisWork = (struct workDetails *) threadarg;
int threadcount = thisWork->threadcount;
int chunkSize = thisWork->chunkSize;
char *serverIp = thisWork->serverIp;
char *dataStore = thisWork->dataStore;
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
char *buffer = (char *) calloc(chunkSize, sizeof(char));
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening client socket");
server = gethostbyname(serverIp);
if (server == NULL) error("Could not detect server by node name");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr,
(char *) &serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(PORTNO);
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("Server is not up.");
long totalPackets = oneGBtoByte / (chunkSize * threadcount);
long i;
for (i = 0; i < totalPackets; ++i) {
sprintf(buffer, "%ld", i);
if (write(sockfd, buffer, chunkSize) < 0)
error("ERROR writing to socket");
else {
lock_guard<mutex> guard(cout_mutex);
cout << " client " << thisWork->threadid << "Wrote " << i << endl;
}
}
cout << " client " << thisWork->threadid << "Exit";
pthread_exit((void *) NULL);
}
void *serverWorker(void *threadarg) {
struct workDetails *thisWork;
thisWork = (struct workDetails *) threadarg;
int threadcount = thisWork->threadcount;
int chunkSize = thisWork->chunkSize;
char *dataStore = thisWork->dataStore;
int sockfd = thisWork->sockfd;
char *buffer = new char[chunkSize];
while (1) {
if(read(sockfd, buffer, chunkSize) > 0){
lock_guard<mutex> guard(cout_mutex);
cout << "Server " << thisWork->threadid << " Received - " << buffer << endl;
}
}
pthread_exit((void *) NULL);
}
【问题讨论】:
-
跨线程共享相同的套接字描述符通常是一个坏主意,如果它是一个 TCP 套接字,它总是一个坏主意(因为您无法控制 TCP 流中的哪些字节将进入哪个线程,并且在不可避免的情况下,线程 A 以传入 TCP 消息的一半结束而线程 B 以另一半结束,这两个线程都无法正确处理消息)
-
我猜整个消息块只发送到一个特定的线程。
read(sockfd, buffer, chunkSize)是线程安全的。 -
您的猜测充其量是过于乐观了。关键是
read(sockfd, buffer, chunkSize)是不保证获得chunkSize字节。特别是,如果您有多个线程共享一个套接字,它可能只接收一个对等方消息的 1 个字节。或者它可能会收到散布的几个对等方消息的字节。代码既可以是线程安全的,也可以是不连贯的。 -
详细说明 Gil 上面提到的——TCP 是一种基于流的协议,而不是基于消息的协议;这意味着 TCP 流只保证它传输的字节的传递和排序,它不提供任何消息帧功能。因此,通过对 send() 的单个调用传递给 TCP 层的数据可能会在另一端通过对 recv() 的多次调用被接收,或者相反,通过对 send() 的多次调用传入的数据可能会通过单个 recv() 调用。您的接收代码需要考虑到这一点——如果涉及多个线程,这很难做到。
-
@sapy:不,他们不是这么说的。您可以有 1 个线程从一个套接字读取,而另一个线程写入同一个套接字。但是你不能有多个线程同时从同一个套接字读取,或者多个线程同时写入同一个套接字,除非你序列化对套接字的访问以避免并发问题和数据损坏。否则,为每个套接字使用单独的线程,不要跨多个线程共享套接字。
标签: c++ multithreading sockets pthreads client-server