【发布时间】:2018-02-17 00:21:02
【问题描述】:
我的代码取自在线资源,如下所示:
//.. initialization and other things..
int connfd = 0;
connfd = accept(listenfd, (struct sockaddr*)&client_address,&client_address_len);
//... other code
pthread_create(&tid, NULL, &foo, &connfd);
上面的代码,将调用带有参数 id 的函数 foo。现在每个线程都有自己的 foo 版本来运行参数。在 foo 中,我可以使用套接字向客户端发送数据。但是,我看不到如何(尽管它工作得很好),是什么链接了线程和套接字。我知道 id 已传递,但它只是一个整数。
这是 foo 函数的样子:
void* SendFileToClient(void *var){
int *connfd;
connfd =(int*) var;
std::cout << "Connection accepted and id:" << *connfd << std::endl;
std::cout << "Connected to Client with IP: " << inet_ntoa(c_addr.sin_addr) << "Port:" << ntohs(c_addr.sin_port) << std::endl; // inet_ntoa converts binary form of IPv4 to IPv4 dotted numbers, ntohs does something silimar for ports
int write_size = write(*connfd, fname,64);
std::cout << write_size << "connfds: " << *connfd << std::endl;
FILE *fp = fopen(fname,"rb");
if(fp==NULL)
{
printf("File opern error");
exit(EXIT_FAILURE);
}
/* Read data from file and send it */
while(1)
{
/* First read file in chunks of 64 bytes */
unsigned char buff[1024]={0};
int nread = fread(buff,1,1024,fp);
/* If read was success, send data. */
if(nread > 0)
{
std::cout << "Sending..." << std::endl;
write_size = write(*connfd, buff, nread);
}
if (nread < 1024)
{
if (feof(fp)) //end of file indicator
{
std::cout << "End of file" << std::endl;
std::cout << "File transfer completed for id:" << *connfd << std::endl;
}
if (ferror(fp))
std::cout << "Error reading" << std::endl;
break;
}
}
std::cout << "Closing Connection for id:" << *connfd << std::endl;
close(*connfd);
shutdown(*connfd,SHUT_WR);
sleep(2);
return NULL;
}
在上面的代码中,调用
write(*connfd, buff, nread);
知道通过 connfd 引用的套接字发送数据。
【问题讨论】:
-
如果您投反对票,请指出什么是错误的,以帮助他人和我自己从否定中获得一些东西。
-
“连接线程和套接字”是什么意思?
-
没有链接,不是真的。就线程而言,它将调用一个函数并传递一个值,该值恰好被该函数用作
int,而int恰好是一个套接字标识符。 -
没有看到其余的代码(因为它没有发布),我最担心的是
id的生命周期。如果它在接受连接的某些执行迭代中,它将在每次迭代时超出范围。将其地址作为传递参数的线程可能在此之前没有获得引用的int值,当您最终获得时,您将处于 UB 领域。这可能非常微妙,因为它很容易看起来“有效”。只有当大量连接入站并且id中的数据开始被覆盖时,事情才会开始看起来很奇怪。 -
@hadis 很容易。一个不需要太多结果的解决方案是通过
intptr_t推送连接描述符。然而,其中涉及相当多的转换,即使代码符合标准,也很容易混淆。另一种解决方案是简单地动态分配int并将接受的连接存储在其中,然后将其作为用户参数传递给pthread_create。最后,让线程 proc 关闭描述符并释放内存。这些方法中的任何一种都不会简单地最小化竞争条件,它会消除它。
标签: c++ function sockets pthreads