티스토리 뷰

데이터 통신

[C++/MFC] UDP Server/Client

개발하는꼬물이 2021. 1. 28. 14:47

보통 TCP/IP만 써왔어서 이번에 UDP 관련코딩은 처음 해보는데,

bind()를 안하면 왜 수신이 안되는 지, 서버에서 sendto()를 먼저 하면 왜 수신이 안되는지 여기저기 찾아보다 알아낸 내용을 정리해본다. 

 

[ UDP (User Datagram Protocol) 통신 ] 

 

 - 전송 계층의 비연결 지향적 프로토콜

 - TCP/IP와 달리 연결 과정이 불필요함 (but, Connect 함수를 사용하는 경우도 존재)

 - 1:1 뿐만 아니라 1:N, N:N 통신이 가능  

 - 흐름제어가 없어 패킷의 전송 순서나 수신 여부에 관한 오류를 확인할 수 없음

 - 신뢰성보다 속도와 성능이 중요시 되는 경우(ex. 실시간서비스)에 사용함

 

UDP/IP 통신에서는 TCP/IP의 read(), write() 대신 recvfrom(), sendto() 함수를 이용해 자료를 송수신한다.

sendto() 함수는 전송할 목적지를 지정할 수 있고, recvfrom() 함수는 수신 데이터와 더불어 송신자의 정보도 얻을 수 있기 때문이다.

 

UDP/IP 통신은 TCP/IP 통신과 달리 클라이언트, 서버의 구분 없이도 데이터를 주고 받을 수 있다.

하지만 연결 과정이 불필요하다 해서 연결없이도 통신이 가능 한 것은 아니고, 수신 측에서 bind()를 통해 소켓에 주소와 포트를 연결시켜줘야 한다. 즉, recvform()을 먼저 호출하는 곳에는 반드시 bind() 함수를 사용해야 한다는 것!

 

* sendto()를 먼저 호출하는 경우는 bind를 해주지 않아도 된다.

이유는, sendto()를 호출 할 때 인자로 주어지는 상대방 주소정보를 참조하여 운영체제가 자동으로 bind를 해주기 때문!

 

혹시 돌아가는 예제가 필요한 사람은 첨부해 둔 Server/Client 코드를 참고 하시길...

단, 메세지 타입은 한글은 지원하지 않으니 적당히 수정해서 쓰길 바람!!

 

** UDP Server 

** UDP Server Receive 

SOCKET m_ServerSocket; 
SOCKADDR_IN m_ServerInfo; 
SOCKADDR_IN m_ClientInfo; 

WSADATA wsa; // Winsock 데이터 구조체

int retVal = 0; 
int nRecvLen = 0; 
char Buffer[1024] = { 0, }; 

//WS2_32.DLL 초기화 
if (WSAStartup(MAKEWORD(2, 2), &wsa) == SOCKET_ERROR) 
{ 
	WSACleanup(); return -1;
}

// UDP Socket 생성 (SOCK_DGRAM : UDP) 
m_ServerSocket = socket(AF_INET, SOCK_DGRAM, 0); 

m_ServerInfo.sin_family = AF_INET; // IPv4 
m_ServerInfo.sin_addr.s_addr = htonl(INADDR_ANY); //Local 
m_ServerInfo.sin_port = htons(12345); 

retVal = bind(m_ServerSocket, (SOCKADDR*)&m_ServerInfo, sizeof(m_ServerInfo)); 

if (retVal == SOCKET_ERROR) 
	return -1; 
    
int nClient_Size = sizeof(m_ClientInfo); 

while (1) 
{ // Recv 대기. Send한 Client 정보 저장 
	nRecvLen = recvfrom(m_ServerSocket, reinterpret_cast<char*>(Buffer), 
    			1024, 0, (SOCKADDR*)&m_ClientInfo, &nClient_Size);
    
    if (nRecvLen > 0)
    { 
    	// RECV 성공 시 MSG 처리.. 
    } 
} 

closesocket(m_ServerSocket); 
WSACleanup(); 



** UDP Server Send 

int sendSize = sendto(m_ServerSocket, reinterpret_cast<char*>(Buffer), 
				nSize, 0, (struct sockaddr*)&m_ClientInfo, sizeof(m_ClientInfo)); 

if (sendSize < 0)
	// Send 실패 시 알림 처리

 

** UDP Cilent

** UDP Client Receive 

BYTE Buffer[884] = { 0,}; 

SOCKET m_clientSock; 
SOCKADDR_IN m_ClientAddr; 

int nSize = sizeof(m_ClientAddr); 
int sendSize = 0; 

while (1) 
{ 
  Recv_Size = recvfrom(m_clientSock, reinterpret_cast<char*>(Buffer), 
  1024, 0, (struct sockaddr*) &m_ClientAddr, &nSize);

  if (Recv_Size >= 0) 
  { 
 	 // RECV 성공 시 MSG 처리..
  } 
} 

closesocket(m_clientSock); //소켓 닫기


** UDP Client Send 

WSADATA wsdata; 
WSAStartup(MAKEWORD(2, 2), &wsdata);

m_clientSock = socket(AF_INET, SOCK_DGRAM, 0); 
ZeroMemory(&m_ClientAddr, sizeof(m_ClientAddr)); 

m_ClientAddr.sin_family = AF_INET; 
m_ClientAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 
m_ClientAddr.sin_port = htons(12345); 

int retval = sendto(m_clientSock, reinterpret_cast<char*>(Buffer),
			0 nLen, 0, (SOCKADDR*)&m_ClientAddr, sizeof(m_ClientAddr)); 

if (retval < 0) 
	// 실패시 알림 처리 

 

 

UDP Server/Client 예제 코드 

 

UDP_ServerClient.7z
다운로드

 

'데이터 통신' 카테고리의 다른 글

Stateful / Stateless Protocol  (0) 2017.08.29
댓글