2017-11-20 1 views
0

클라이언트 인 C++의 UDP 소켓과 한 번에 서버에서 작업하고 있습니다. Visual Studio 2017을 사용하고 Windows 7에서 실행합니다. "invalid argument"오류로 끝나는 recvfrom() 함수에 몇 가지 문제가 있습니다. 난 소켓 괜찮아 sockaddr_in 구조체 괜찮아요, 스레드 괜찮아요, 심지어 sendto() 함수와 함께 while 루프 괜찮아요 생각합니다. 그러나winsock2 : recvfrom() 함수가 10022 오류로 끝납니다 (잘못된 인수)

#include <iostream> 
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <winsock2.h> 
#include <thread> 

#pragma comment(lib, "Ws2_32.lib") 

using namespace std; 

void printMessage(SOCKET s, SOCKADDR_IN destAddr) { 

    char message[100]; 
    int result, error; 
    int addrSize = sizeof(destAddr); 
    do { 
     printf("som v threade\n"); 
     result = recvfrom(s, message, 100, 0, (SOCKADDR*)&destAddr, &addrSize); 
     printf("%d\n", result); 

     if (result < 0) { 
      error = WSAGetLastError(); 
      printf("%d\n", error); 
     } 

     if (result > 0) 
      printf("%s", message); 

    } while (result > 0); 

} 


int main(int argc, char *argv[]) { 

    WORD dllVersion = MAKEWORD(2, 1); 
    WSADATA wsaData; 

    if (WSAStartup(dllVersion, &wsaData) != 0) { 
     printf("Winsock startup failed"); 
     exit(1); 
    } 

    const char *ip = "127.0.0.1"; 
    int dstPort = 49999; 
    int srcPort = 49999; 

    SOCKADDR_IN destaddr, srcaddr; 
    SOCKET s; 
    s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 

    if (s < 0) { 
     printf("Error creating socket"); 
     exit(1); 
    } 

    destaddr.sin_family = AF_INET; 
    destaddr.sin_addr.s_addr = inet_addr(ip); 
    destaddr.sin_port = htons(dstPort); 

    srcaddr.sin_family = AF_INET; 
    srcaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    srcaddr.sin_port = htons(srcPort); 


    bind(s, (SOCKADDR*)&srcaddr, sizeof(srcaddr)); 

    thread receiving (printMessage, s, destaddr); 
    receiving.detach(); 

    while (1) { 
     char message[100]; 

     printf("Write a message:"); 
     scanf("%s", message); 

     if (sendto(s, message, sizeof(message), 0, (SOCKADDR *) &destaddr, sizeof(destaddr)) < 0) { 
      printf("Message not sent"); 
      exit(1); 
     } 
    } 
    return 0; 
} 
+0

당신은'바인딩 오류 검사되지 않습니다()':

이와 비슷한 더 많은 것을보십시오. 'printf()'나 다른 시스템 호출을하기 전에'WSAGetLastError()'*를 호출해야하고 매번 루프를 돌 때마다'addrSize'를 재 초기화해야합니다. – EJP

답변

1

오류 코드 10022은 WSAEINVAL입니다 ... 스레드는에 recvfrom() 함수를 호출 한 후 종료하고 문제가 어디 있는지 난 정말 모르겠어요. recvfrom() 문서 당 :

WSAEINVAL

을 소켓은 bind()에 연결되지 않았거나 알 수없는 플래그가 지정, 또는 MSG_OOB는 바이트 스트림 (활성화 SO_OOBINLINE와 소켓의 지정, 또는 한 스타일 소켓 만 해당) len은 0 또는 음수입니다.

bind() 호출이 실패하지 않았는지 확인하기 위해 오류 처리를 수행하고 있지 않습니다. 또는 올바른 bind() 함수를 호출한다고해도 마찬가지입니다. WinSock과 STL은 모두 자신의 bind() 기능을 가지고 있지만, use of using namespace std masks that fact.

또한 recvfrom()으로 전화 할 때마다 addrSize을 재설정해야합니다. 값을 수정할 수 있습니다. 그것은 당신이 당신의 최대 버퍼 크기를 넘기를 기대하고, 버퍼에 실제로 기록 된 크기를 출력합니다.

또한 적절한시기에 WSAGetLastError()으로 전화하지 않습니다. 실패한 WinSock 호출 후 으로 즉시으로 전화해야합니다. 을 입력하기 전에을 입력해야합니다. 즉, WSAGetLastError()으로 전화하기 전에 printf()으로 전화하지 마십시오. 잠재적으로 오류 코드가 재설정 될 수 있습니다.

또한 recvfrom()이 성공적으로 읽으면 데이터가 null로 끝났다고 가정하지만이를 보장 할 수는 없습니다. 매개 변수로 resultprintf()에 전달해야합니다.

그리고 C 스타일 I/O와 C++을 혼합해서는 안됩니다. 대신 C++ 스타일 I/O를 사용하십시오.

#include <iostream> 
#include <string> 
#include <thread> 
#include <winsock2.h> 

#pragma comment(lib, "Ws2_32.lib") 

void printMessage(SOCKET s) 
{ 
    char message[100]; 
    int result, error, addrSize; 
    SOCKADDR_IN clientaddr; 

    do { 
     std::cout << "som v threade" << std::endl; 
     addrSize = sizeof(clientaddr); 
     result = recvfrom(s, message, 100, 0, (SOCKADDR*)&clientaddr, &addrSize); 
     if (result == SOCKET_ERROR) { 
      error = WSAGetLastError(); 
      std::cout << "Receive failed. Error: " << error << std::endl; 
      continue; 
     } 
     std::cout << "Received " << result << " byte(s) from " << inet_ntoa(clientaddr.sin_addr) << ":" << ntohs(clientaddr.sin_port) << std::endl; 
     if (result > 0) { 
      std::cout.write(message, result); 
      std::cout << std::endl; 
     } 
    } 
    while (result > 0); 
} 

int main(int argc, char *argv[]) { 
    WORD dllVersion = MAKEWORD(2, 1); 
    WSADATA wsaData;  
    int result, error; 

    result = WSAStartup(dllVersion, &wsaData); 
    if (result != 0) { 
     std::cout << "Winsock startup failed. Error: " << result << std::endl; 
     exit(1); 
    } 

    SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
    if (s == INVALID_SOCKET) { 
     error = WSAGetLastError(); 
     std::cout << "Socket creation failed. Error: " << error << std::endl; 
     exit(1); 
    } 

    const char *ip = "127.0.0.1"; 
    unsigned short dstPort = 49999; 
    unsigned short srcPort = 49999; 

    SOCKADDR_IN destaddr = {}; 
    SOCKADDR_IN srcaddr = {}; 

    destaddr.sin_family = AF_INET; 
    destaddr.sin_addr.s_addr = inet_addr(ip); 
    destaddr.sin_port = htons(dstPort); 

    srcaddr.sin_family = AF_INET; 
    srcaddr.sin_addr.s_addr = INADDR_ANY; 
    srcaddr.sin_port = htons(srcPort); 

    result = ::bind(s, (SOCKADDR*)&srcaddr, sizeof(srcaddr)); 
    if (result == SOCKET_ERROR) { 
     error = WSAGetLastError(); 
     std::cout << "Socket bind failed. Error: " << error << std::endl; 
     exit(1); 
    } 

    std::thread receiving(printMessage, s); 
    receiving.detach(); 

    std::string message; 
    do { 
     std::cout << "Write a message: "; 
     std::getline(std::cin, message); 
     result = sendto(s, message.c_str(), message.size(), 0, (SOCKADDR *) &destaddr, sizeof(destaddr)); 
     if (result == SOCKET_ERROR) { 
      error = WSAGetLastError(); 
      std::cout << "Message not sent. Error: " << error << std::endl; 
      exit(1); 
     } 
    } 
    while (true); 

    return 0; 
} 
관련 문제