2013-07-04 2 views
1

매우 간단하게 작동하는 매우 다른 recvfrom() 명령이 있습니다. "다른"스레드에서 호출되지 않는 한 그렇습니다.멀티 스레드 일 때 소켓이 작동하지 않는 이유는 무엇입니까?

더 많은 코드를 게시 할 예정이지만 관련 정보를 필터링 할 수 있습니다. 먼저 글로벌 변수 SOCKET Socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);이 있습니다.

너무 오래 스레드가 관여하지 않습니다,이 잘 작동 :

지금은 다음과 같이 스레드 뒤에 동일한 코드를 불렀다
char message[_max_message_]; 
struct sockaddr_in* from; 
int r; 
    int SenderAddrSize = sizeof (struct sockaddr); 
    r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize); 
    printf("Bytes recieved: %i\nError Code: %i\n",r,WSAGetLastError); 

: (. 코드는 기본적으로 &socket을 무시) 이 pthread_create(&listener, NULL, listenloop, &Socket);

호출 대상 스레드에서 실행될 첫 번째 recvfrom()은 -1을 반환하지만 "원본"스레드 (네트워킹이 설정된 곳)에서 recvfrom()을 반환합니다. up)은 message을 성공적으로 서버의 메시지로 채 웁니다.

제가 뭘 잘못하고 있는지 말해 주시겠습니까?

편집 : 나를 돕기에 충분히 친절한 낯선 사람들에게 12 줄 넘는 줄을 던지기는하지만, 그렇지 않으면 대답을 얻지 못할 것이라고 생각합니다. 여기 키트와 카 들레가 약간 수정되었습니다 :

#include <iostream> 
//#include <stdio.h> 
#include <stdlib.h> 
#include <stdio.h> 

#include <pthread.h> 
#include <conio.h> 

using namespace std; 
#include <string> 
//One thread shall listen continually for responses from the server. 
/*The other thread shall listen continually for user input, and fire off user input at the local 
client to the server...*/ 

//#ifdef _WINDOWS 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <windows.h> 

SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
inline int randport() 
{ 
    return (50000 % rand() + 1000); 
} 
#define _serverip_ "***.***.***.***" 
#define _welcome_ "Welcome,Wagon!" 

#define _randomport_ 64000%rand()+100 
#define _max_message_ 100 

void *listenloop(void *arg) 
{ 
    //SOCKET* listener = (SOCKET)arg; 
    WSADATA WsaDat; 
    WSAStartup(MAKEWORD(2, 0), &WsaDat); 

    char message[_max_message_]; 
    //SOCKET listener=(SOCKET)arg; 
    int r; 
    //sockaddr_in SenderAddr; 
    struct sockaddr_in from; 
    //while (1){ 

    int SenderAddrSize = sizeof(struct sockaddr); 
    r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from, 
     &SenderAddrSize); 
    printf("Thread Bytes recieved: %i\nThread Error Code: %i\n", r, 
     WSAGetLastError); 
    return NULL ; 

    //} 
    return NULL ; 
} 

int main() 
{ 
    string user, pass, login; 
    WSADATA WsaDat; 
    WSAStartup(MAKEWORD(2, 0), &WsaDat); 
    int port; 
    cout << "Welcome!" 
    SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 

    fflush(stdin); //As long as we compile with GCC Behavoir should be consistant 

    //TRY NOT TO SEND PLAINTEXT PASSWORDS LIKE THIS! IT MAY MAKE YOUR USERS VULNERABLE! DONE FOR SAKE OF SIMPLICITY HERE! 

    cout << "\n\nPlease enter the username you registered with:"; 
    getline(cin, user); 
    cout << "\nPlease enter your password, my good sir: "; 
    getline(cin, pass); 
    struct hostent *host; 
    host = gethostbyaddr(_serverip_, strlen(_serverip_), AF_INET); 

    if (host == NULL) 
    { 
    cout << "\n\n UNABLE TO CONNECT TO SERVER. QUITTING. "; 
    return -1; 
    } 

    short errorcount = 3; 
    int socketfeedback; 

    ///Put the address for the server on the "evelope" 

    SOCKADDR_IN SockAddr; 
    SockAddr.sin_port = htons(port); 
    SockAddr.sin_family = AF_INET; 
    SockAddr.sin_addr.s_addr = inet_addr(_serverip_); 

    ///Sign the letter... 

    int myport = _randomport_; 
    int code; 

    SOCKADDR_IN service; 
    service.sin_family = AF_INET; 
    service.sin_addr.s_addr = inet_addr("localhost"); 
    service.sin_port = htons(myport); 

    //bind(Socket, (SOCKADDR *) &service, sizeof(service)); 

    //Start a thread, listening for that server 

    while ((errorcount)) 
    { 
    code = bind(Socket, (SOCKADDR *) &service, sizeof(service)); 
    if (code) 
     break; 
    else 
     return -5; 
    errorcount--; 
    myport = _randomport_; 
    service.sin_port = htons(myport); 
    } 

    login = user + ',' + pass; 

    if (!errorcount) 
    { 
    cout << "\n\nMiserable failure. Last Known Error Code: " << code; 
    return -1; 
    } 

    ///Begin the listen loop!! 

    pthread_t listener; 
    pthread_create(&listener, NULL, listenloop, &Socket); 
    struct sockaddr result; 
    sendto(Socket, login.c_str(), strlen(login.c_str()), 0, 
     (struct sockaddr *) &SockAddr, sizeof(SockAddr)); 

    char message[_max_message_]; 
    //SOCKET listener=(SOCKET)arg; 

    //sockaddr_in SenderAddr; 
    struct sockaddr_in from; 
    int r; 
    int SenderAddrSize = sizeof(struct sockaddr); 
    r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from, 
     &SenderAddrSize); 
    printf("Bytes recieved: %i\nError Code: %i\n", r, WSAGetLastError); 

    //SOCKET listener=(SOCKET)arg; 

    WSACleanup(); 

    return 0; 

} 
+0

반환 값 -1과 관련된'errno'는 무엇입니까? 이런 일이 생길 때'perror'라고 부르십시오. 나는, 감사합니다 ... – EJP

+0

는 WSAgetlast 오류에 따르면 ... 그것은 매우 큰 숫자이지만, 작업 및 휴무'recvfrom' 년대 모두 같은 수의, 그래서 나는 그것이 어떤 종류의 단지 유물라고 생각 했어요 '는 WINSOCK이 수 – user1833028

+0

http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html perror는 시도 할 것이다 ** 매우 ** 재미있을 것입니다. 그걸 우리 한테 보여줄 수 있니? – user1833028

답변

0

댓글에 너무 깁니다.

때문에 선언에 전혀 작동하지 않을 것입니다 게시 된 코드 : 다음

struct sockaddr_in* from; 

이 같은 from 사용 : 당신은 대신 struct sockaddr_in의 주소의 주소를 paasing하는

r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize); 

을 그 주소 만.

는 다음과 같다인가 :

r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)from,&SenderAddrSize); 

그러나 당신이 from에 메모리를 할당 누락 그렇게하는 경우.

그래서 propably

struct sockaddr_in* from; 

오타이고 읽어야 :

struct sockaddr_in from = {0}; 

?

+0

선생님 ... 내가 이해할 수 있도록 변경 사항을 구현했습니다. 그들은 코드의 동작에 영향을주지 않았습니다. – user1833028

1

왜 글로벌 Socket을 사용합니까? 그리고 왜 다른 메인을 Socket이라고 선언하고 있습니까? pthread_create에 전달 된 소켓을 사용하는 것이 좋습니다. SOCKET *의 listenloop에 args을 캐스트하면됩니다. 다중 스레드에서 전역 변수는 정말 나쁜 생각입니다 (동기화 메커니즘이 필요합니다). struct sockaddr_in from을 0으로 초기화하십시오 (예 : memset으로 입력하거나 알콜이라고 말한 것 : struct sockaddr_in from = {0}).

또한 당신은 동기화의 어떤 종류없이 두 개의 서로 다른 스레드에서 하나의 소켓에서 읽고있다. 이 오류로 인해 많은 오류가 발생할 수 있습니다.

는 또한 나는 다른 스레드에서 WSACleanuprecvfrom 문제를 참조하십시오. 당신이 모르는 어떤 순서 것이다이 두 실행 우선은 완료하고 WSACleanup을 수행하는 다른 스레드를 기다리는 pthread_join을 사용할 수 있습니다 (당신이 recvfrom 다른 스레드 전에 그래서 당신은 또한 WSACleanup를 얻을 수 있습니다).

관련 문제