3

我正在尝试使用 UDP 制作网络系统。我已经设法让它工作了,但现在我想把监听部分放在一个单独的线程中,这样我就可以继续程序而不必等待消息(它将用于游戏)。

问题是,当我将套接字传递给新线程并将其用于侦听时,它不起作用,只是不断地接收随机输入。当我在初始化套接字的方法中使用完全相同的代码时,一切正常。

这有效:

bool serverUDP() {
WSADATA w;
SOCKET sd;

struct sockaddr_in server, client;
char buffer[DEFAULT_BUFLEN];
int bytes_received;
int client_length;

/* Open windows connection */
if (WSAStartup(MAKEWORD(2,2)/*0x0101*/, &w) != 0) {
    fprintf(stderr, "Could not open Windows connection.\n");
    return false;
}

/* Open a datagram socket */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == INVALID_SOCKET) {
    fprintf(stderr, "Could not create socket.\n");
    WSACleanup();
    return false;
}

/* Clear out server struct */
memset((void *)&server, '\0', sizeof(struct sockaddr_in));

/* Set family and port */
server.sin_family = AF_INET;
server.sin_port = htons(atoi(DEFAULT_PORT));

server.sin_addr.S_un.S_un_b.s_b1 = 127;
server.sin_addr.S_un.S_un_b.s_b2 = 0;
server.sin_addr.S_un.S_un_b.s_b3 = 0;
server.sin_addr.S_un.S_un_b.s_b4 = 1;

/* Bind address to socket */
if (bind(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1) {
    fprintf(stderr, "Could not bind name to socket.\n");
    closesocket(sd);
    WSACleanup();
    return false;
}

client_length = (int)sizeof(struct sockaddr_in);

/* Receive bytes from client */
while (true) {
    bytes_received = recvfrom(sd, buffer, DEFAULT_BUFLEN, 0, (struct sockaddr *)&client, &client_length);
    fprintf(stderr,"received: %s\n", buffer);
}

closesocket(sd);
WSACleanup();   

return true;
}

这不会:

bool serverUDP() {
WSADATA w;
SOCKET sd;

struct sockaddr_in server, client;
char buffer[DEFAULT_BUFLEN];
int bytes_received;
int client_length;

/* Open windows connection */
if (WSAStartup(MAKEWORD(2,2)/*0x0101*/, &w) != 0) {
    fprintf(stderr, "Could not open Windows connection.\n");
    return false;
}

/* Open a datagram socket */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == INVALID_SOCKET) {
    fprintf(stderr, "Could not create socket.\n");
    WSACleanup();
    return false;
}

/* Clear out server struct */
memset((void *)&server, '\0', sizeof(struct sockaddr_in));

/* Set family and port */
server.sin_family = AF_INET;
server.sin_port = htons(atoi(DEFAULT_PORT));

server.sin_addr.S_un.S_un_b.s_b1 = 127;
server.sin_addr.S_un.S_un_b.s_b2 = 0;
server.sin_addr.S_un.S_un_b.s_b3 = 0;
server.sin_addr.S_un.S_un_b.s_b4 = 1;

/* Bind address to socket */
if (bind(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1) {
    fprintf(stderr, "Could not bind name to socket.\n");
    closesocket(sd);
    WSACleanup();
    return false;
}

_beginthread((void(*)(void*))receiveThread,0,(void *)sd);

closesocket(sd);
WSACleanup();   

return true;
}

void receiveThread(SOCKET sd)
{
struct sockaddr_in client, server;
char buffer[DEFAULT_BUFLEN];

int bytes_received;
int client_length;

client_length = (int)sizeof(struct sockaddr_in);

while (true) {
    bytes_received = recvfrom(sd, buffer, DEFAULT_BUFLEN, 0, (struct sockaddr *)&client, &client_length);
    fprintf(stderr,"received: %s\n", buffer);
}
}

第二段代码只是随机输入垃圾邮件,就好像它不断收到一些奇怪的消息一样。第一段代码等待消息并在收到消息时继续(我也有一个客户端部分)。

谢谢你的帮助!

干杯,

马克西姆·舒梅克

4

5 回答 5

4

主线程在启动另一个线程后立即关闭套接字。因此线程不再具有有效的套接字句柄。

于 2012-06-29T16:56:58.270 回答
3

您的问题的根源是这一行:

_beginthread((void(*)(void*))receiveThread,0,(void *)sd);

基本上,您使用receiveThread()错误的参数调用函数,但是您欺骗了编译器使其无法检测到错误的情况:您将函数转换为错误的签名并将参数转换为错误的类型。

更改receiveThread()函数以使其具有正确的签名,然后删除强制转换。

void * receiveThread(void * context);

_beginthread(receiveThread,0,(void *)sd);

然后,将指针传递给您的sd变量并在线程函数中引用它:

_beginthread(receiveThread,0,&sd);


void * receiveThread(void * context)
{
    SOCKET socket = *(SOCKET*)context;
    // ...
}
于 2012-06-29T16:45:19.553 回答
1
(void *)&sd

void receiveThread(void *param)

SOCKET sd = *(SOCKET *)param;

我认为它应该解决它!

编辑:

写 (void *)sd 创建一个指向 sd 值地址的指针,这是错误的,你需要创建一个指向 sd 地址的指针,所以你写 &sd,这样你就可以在取消线程函数后获取它的值通过取消引用它: SOCKET sd = (SOCKET)*param;

我的英语不是很好,我希望你能理解。

于 2012-06-29T16:40:49.360 回答
0

该程序应读取(sudo 代码):

 while(1){
 listen()
 newSD = accept()
 pthread_creat(newsd)

}

这将为每个连接创建一个新线程,同时保持 main 运行

于 2012-08-23T01:14:34.533 回答
0

在关闭主函数中的套接字之前,您必须尝试包含 WaitForSingleObject() 。

于 2017-04-25T20:21:09.370 回答