将套接字传递给线程C.

时间:2012-06-29 16:37:53

标签: c++ c multithreading sockets

我正在尝试使用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);
}
}

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

感谢您的帮助!

干杯,

Maxim Schoemaker

5 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分: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;
    // ...
}

答案 2 :(得分:1)

(void *)&sd

void receiveThread(void *param)

SOCKET sd = *(SOCKET *)param;

我认为它应该解决它!

编辑:

写(void *)sd创建一个指向sd值地址的指针,这是错误的,你需要创建一个指向sd地址的指针,所以你写& sd,这样你就可以得到它的值了通过dereferrencing它是线程函数:SOCKET sd =(SOCKET)* param;

我的英语不是那么好,我希望你明白。

答案 3 :(得分:0)

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

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

}

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

答案 4 :(得分:0)

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