2011-11-11 2 views
1

저는 TCP로 꽤 오래 동안 프로그래밍을 해왔고 UDP를 선택하기로했습니다. 나는 WAN에서 통신을 할 때 (또는 단지 두 개의 포트를 열 수 있기 때문에 lan에서 더 쉽게) WAN을 통해 통신 할 수 있도록하기 위해 무엇을해야하는지 잘 모르겠습니다. 일단 클라이언트에서 정보를 UDP로 보내면 서버 어떻게 그 소켓에서 응답 할 수 있습니다. 직접 연결할 수있는 방법이 있습니까?UDP는 연결된 소켓에서 응답합니다.

(현재 빠른 기능)이이 포트 XXXX와 소켓을하고 클라이언트에 데이터를 얻기 위해 해당 포트에 보내는 파트너가 꽤 쉽게와

int udpsock(int port, const char* addr){ 
int handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
if (handle < 1) 
    return -1; 

sockaddr_in address; 
address.sin_family = AF_INET; 
if (addr == INADDR_ANY) 
    address.sin_addr.s_addr = INADDR_ANY; 
else 
    address.sin_addr.s_addr = inet_addr(addr); 
address.sin_port = htons((unsigned short) port); 

if (bind(handle, (const sockaddr*) &address, sizeof(sockaddr_in)) < 0) 
    return -1; 

return handle; 
} 
string recvudp(int sock,const int size){ 
sockaddr_in SenderAddr; 
int SenderAddrSize = sizeof (SenderAddr); 
char buf[size]; 

int retsize = recvfrom(sock, buf, sizeof(buf), 0, (SOCKADDR *) & SenderAddr, &Sen derAddrSize); 
if (retsize == -1){ 
    cout << "\nRecv Error : " << WSAGetLastError(); 
    if (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == 0){ 
     return ""; 
    } 
    return "\0"; 
} 
else if (retsize < size){ 
    buf[retsize] = NULL; 
} 
return buf; 
} 
int sendudp(string str, string ip, unsigned short port, int sock){ 
sockaddr_in dest; 
dest.sin_family = AF_INET; 
dest.sin_addr.s_addr = inet_addr(ip.c_str()); 
dest.sin_port = htons(port); 

int ret = sendto(sock,str.c_str(),str.size(),0, (sockaddr*)&dest,sizeof(dest)); 

if (ret == -1){ 
    cout << "\nSend Error Code : " << WSAGetLastError(); 
} 

return ret; 
} 

나는 '경우, 등 부분은 어떤 문제가있는 m =]

+0

UDP가 연결되어 있지 않아 연결할 수 없습니다.요청을 처리하고 sendto를 사용하여 전송합니다. UDP 클라이언트는 또한 서버 데이터를 받기 위해 서버 여야합니다 ... – neagoegab

+2

UDP 소켓에서 connect()를 호출하여 "연결"할 수 있습니다. 하지만 실제로는 TCP 의미의 연결이 아닙니다. send()를 호출 할 때 패킷을 보낼 IP 주소를 네트워크 스택에 알려주는 숨겨진 변수를 설정하는 것과 같습니다. 아마도 sendto()가 잘 작동하고 이해하기가 쉽기 때문에 아마 신경 쓰지 않아도 될 것입니다. –

답변

2

내가 게시 한 기능이 클라이언트와 서버간에 공유되어야한다고 가정합니다. 이를 달성하기 위해서는 약간 수정해야합니다. 예 : 서버 측에서 recvudp은 나중에 메시지를 다시 보내는 데 필요한대로 클라이언트 주소 (가능하면 out 매개 변수)를 반환해야합니다. 또한 클라이언트 주소 구조가 이미 채워져 있으므로 (서버 측의 recvudp 또는 클라이언트 측의 수동으로) sendudp을 인수로 전달할 수 있습니다.

Visual Studio 2010에서는 두 가지 간단한 프로젝트 (UDP 서버 및 클라이언트)를 만들었습니다. 둘 다 위에서 언급 한 공유 기능을 사용합니다. 이 코드는 완벽하지 않으며 기본적인 UDP 소켓 통신 만 보여줍니다.

Shared.h :

#ifndef SHARED_H 
#define SHARED_H 
#include <winsock2.h> 
#include <string> 

int udpsock(int port, const char* addr); 
std::string recvudp(int sock, const int size, sockaddr_in& SenderAddr, int& SenderAddrSize); 
int sendudp(std::string str, sockaddr_in dest, int sock); 

#endif 

Shared.cpp :

#include "Include\shared.h" // path to header - you might use different one 
#include <iostream> 
using namespace std; 

int udpsock(int port, const char* addr) 
{ 
    int handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 

    if (handle < 1) 
     return -1; 

    sockaddr_in address; 
    address.sin_family = AF_INET; 
    if (addr == INADDR_ANY) 
     address.sin_addr.s_addr = INADDR_ANY; 
    else 
     address.sin_addr.s_addr = inet_addr(addr); 
    address.sin_port = htons((unsigned short) port); 

    if (bind(handle, (const sockaddr*) &address, sizeof(sockaddr_in)) < 0) 
     return -1; 

    return handle; 
} 

// function should return sender address info (for the code the server) 
string recvudp(int sock, const int size, sockaddr_in& SenderAddr, int& SenderAddrSize) 
{ 
     // TODO: use std::vector<char> here instead of char array 
    char* buf = 0; 
    buf = new char[size]; 

    int retsize = recvfrom(sock, buf, size, 0, (sockaddr*) &SenderAddr, &SenderAddrSize); 

    if(retsize == -1) 
    { 
     cout << "\nRecv Error : " << WSAGetLastError(); 

     if (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == 0) 
     { 
      return ""; 
     } 

     return "\0"; 
    } 
    else if (retsize < size) 
    { 
     buf[retsize] = NULL; 
    } 

    string str(buf); 
    delete[] buf; 

    return str; 
} 

// On the client side, prepare dest like this: 
// sockaddr_in dest; 
// dest.sin_family = AF_INET; 
// dest.sin_addr.s_addr = inet_addr(ip.c_str()); 
// dest.sin_port = htons(port); 
int sendudp(string str, sockaddr_in dest, int sock) 
{ 
    int ret = sendto(sock,str.c_str(),str.size(),0, (sockaddr*)&dest,sizeof(dest)); 

    if (ret == -1) 
    { 
     cout << "\nSend Error Code : " << WSAGetLastError(); 
    } 

    return ret; 
} 

서버 : MAIN.CPP :

#include <winsock2.h> 
#include <string.h> 
#include <iostream> 
#include "..\Shared\Include\shared.h" 

// Link with ws2_32.lib 
#pragma comment(lib, "Ws2_32.lib") 

#define SERVER_PORT 27015 
#define MAX_MSG 1024 

using namespace std; 

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

    int nResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 

    if(nResult != NO_ERROR) 
    { 
     cout << "WSAStartup failed with error: " << nResult << endl; 
     return 1; 
    } 

    sock = udpsock(SERVER_PORT, "127.0.0.1"); 
    cout << "Waiting for datagram on port: " << SERVER_PORT << endl; 

    while(1) 
    { 
     sockaddr_in clientAddr;  
     // receive message 
     int clientAddrLen = sizeof(clientAddr); 

     cout << "Received message from the client: " << recvudp(sock, MAX_MSG, clientAddr, clientAddrLen) << endl; 

     sendudp("Hello from server!", clientAddr, sock); 
    } 

    WSACleanup(); 
    return 0; 
} 

클라이언트 : MAIN.CPP :

#include <winsock2.h> 
#include <iostream> 
#include "..\Shared\Include\shared.h" 
using namespace std; 

#define MAX_MSG 1024 

// Link with ws2_32.lib 
#pragma comment(lib, "Ws2_32.lib") 

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

    int nResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
    if (nResult != NO_ERROR) 
    { 
     cout << "WSAStartup failed with error: " << nResult << endl; 
     return 1; 
    } 

    SOCKET sock = INVALID_SOCKET; 

    // Create a socket for sending data - it does not need to be binded like listening socket! 
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 

    if(sock == INVALID_SOCKET) 
    { 
     cout << socket failed with error: " << WSAGetLastError() << endl; 
     WSACleanup(); 
     return 1; 
    } 

    unsigned short Port = 27015;  

    sockaddr_in dest; 
    dest.sin_family = AF_INET; 
    dest.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    dest.sin_port = htons(Port); 

    sendudp("Hello from client!", dest, sock); 

    sockaddr_in RecvAddr;  
    int recvaddrlen = sizeof(RecvAddr); 

    cout << "Received message from the server: " << recvudp(sock, MAX_MSG, RecvAddr, recvaddrlen) << endl; 

    cout << "Closing socket..." << endl; 

    nResult = closesocket(sock); 

    if(nResult == SOCKET_ERROR) 
    { 
     cout << "closesocket failed with error: " << WSAGetLastError() << endl; 
     WSACleanup(); 
     return 1; 
    } 

    WSACleanup(); 
    return 0; 
} 
당신이 클라이언트를 실행하면

두 번 출력은 다음과 같습니다

서버 :

포트에 데이터 그램을 기다리는 : 27015
수신 된 메시지를 클라이언트에서 : 안녕하세요 클라이언트에서!
클라이언트로부터받은 메시지 : 안녕하세요.

클라이언트 :

안녕하세요 서버!
닫기 소켓 ...

UDP는 비 연결 프로토콜, 서버는 단지 데이터 (데이터 그램) 즉시, connect()/accept()와 연결 설정 (예 : 필요가 같이 존재하지를 보낼 수 UDP 포트와 클라이언트에서 음악을 감상 할 필요가있다 TCP).

+0

Perfect- 꽤 거의 정확히 David 's Answer (Dratted multiple answers)를 기반으로 구현 한 것입니다. 응답의 깊이에 대해 감사드립니다. – ultifinitus

+0

도움이 되었기 때문에 기쁩니다 :) –

3

sendudp 함수가 sockaddr_in이되도록하십시오. 당신은 recvfrom에서 1을 되찾고 sendto에 그것을 건네 줄 수있다. 또는 수신 된 sockaddr_inconnect으로 전달한 다음 send을 사용하십시오.

+0

오, 알겠습니다. 나는이 기회를 빨리 줄 것이다! 감사! – ultifinitus

+0

완벽했습니다. 정확히 내가 필요로하는 것. 고맙습니다. – ultifinitus

관련 문제