WinSock 네트워크 프로그래밍 기본(2) 클라이언트

다음은 WinSock으로 TCP/IP 모델을 기반으로 하는 클라이언트와 서버를 만드는 방법에 대해 설명합니다.
TCP는 두 컴퓨터 간의 신뢰할 수 있는 데이터 전송을 제공할 수 있으며 응용 프로그램이 TCP 통신을 사용할 때 두 컴퓨터 사이에 가상 연결을 구축하고 연결된 후에 컴퓨터 간에 양방향 바이트 흐름으로 데이터 교환을 할 수 있다.
다음은 간단하게 데이터를 보내는 클라이언트의 실현입니다.
클라이언트의 연결을 쉽게 만들 수 있습니다.
 

1. 플러그인을 만들고 addrinfo 대상을 정의하고 이 값을 초기화합니다 (이 대상은 sockaddr 구조를 포함합니다)

struct addrinfo *result = NULL,

                *ptr = NULL,

                hints;



ZeroMemory( &hints, sizeof(hints) );

hints.ai_family = AF_UNSPEC;  // IPv4 IPv6 

hints.ai_socktype = SOCK_STREAM;

hints.ai_protocol = IPPROTO_TCP;


 
getaddrinfo 함수를 호출하여 서버 IP 주소 (명령행 매개 변수로 전달) 와 포트를 확인합니다.
#define DEFAULT_PORT "27015"



// Resolve the server address and port

iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);

if (iResult != 0) {

    printf("getaddrinfo failed: %d
", iResult); WSACleanup(); return 1; }

 
socket 프로토타입:
socket( 
IN int af,//프로토콜의 주소족, IPv4를 사용하여 Winsock을 설명하고 AF 로 설정INET 
IN int type,//소켓 유형, TCP/IP SOCKSTREAM, UDP/IP를 SOCK 로 설정DGRAM 
IN int protocol//지정된 주소 패밀리 및 유형에 다중 포털이 있는 전송 제한을 위해 TCP를 IPPROTO 로 설정TCP, UDP를 IPPROTO 로 설정UDP 
       ); 
socket을 호출하여 플러그인 생성, 오류 검출
SOCKET ConnectSocket = INVALID_SOCKET;

ptr=result;

ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 

    ptr->ai_protocol);

if (ConnectSocket == INVALID_SOCKET) {

    printf("Error at socket(): %ld
", WSAGetLastError()); freeaddrinfo(result); WSACleanup(); return 1; }

 


2. 접속된 서버 이름입니다.(TCP/IP에서 수신 서버의 IP 주소와 포트 번호)

iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);

if (iResult == SOCKET_ERROR) {

    closesocket(ConnectSocket);

    ConnectSocket = INVALID_SOCKET;

}

// 

freeaddrinfo(result);



if (ConnectSocket == INVALID_SOCKET) {

    printf("Unable to connect to server!
"); WSACleanup(); return 1; }

 
클라이언트 프로그램은 플러그인을 만든 후에 연결 함수를 사용하여 서버와 연결을 요청합니다. 연결 원형은 다음과 같습니다.
int WSAAPI connect( 
IN SOCKET s,//연결할 socket
IN construct sockaddr FAR * name,//연결 정보를 저장할 주소 구조를 나타냅니다.
IN int namelen//매개변수 2는 주소 구조의 크기를 가리킵니다.
        ); 

 


3. 데이터를 보내고 받는다.


 
데이터를 수발하는 것이야말로 네트워크 프로그래밍의 주제이다. 이미 연결된 플러그인에 데이터가 발생하면send나 WSASend(WinSock2에서)를 사용할 수 있고recv와 WSARecv를 사용할 수 있다.송수신 데이터는char 형식을 사용합니다.
#define DEFAULT_BUFLEN 512



int recvbuflen = DEFAULT_BUFLEN;



char *sendbuf = "this is a test";

char recvbuf[DEFAULT_BUFLEN];



int iResult;



iResult = send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0);

if (iResult == SOCKET_ERROR) {

    printf("send failed: %d
", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } printf("Bytes Sent: %ld
", iResult); iResult = shutdown(ConnectSocket, SD_SEND); if (iResult == SOCKET_ERROR) { printf("shutdown failed: %d
", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } do { iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0); if (iResult > 0) printf("Bytes received: %d
", iResult); else if (iResult == 0) printf("Connection closed
"); else printf("recv failed: %d
", WSAGetLastError()); } while (iResult > 0);

 
송수신 데이터가 반환되는 모든 오류 코드는 SOCKETERROR, 오류가 발생하면 WSAGetLastError () 를 호출하여 자세한 오류 정보를 가져옵니다.
자주 발생하는 오류:
WSAECONNABORTED와 WSAECONNRESET: 연결이 닫히고 있습니다(시간 초과 또는 통신 방송으로 연결이 닫히고 있음). WSAEWOULDBLOCK: 소켓이 비막힘 모드 또는 비동기 상태입니다.
send와recv 함수 원형을 사용합니다.
int send(
SOCKET s,//소켓 핸들
const char FAR* buf,//보낼 데이터의 버퍼 주소
int len,//버퍼 길이
int flags//에서 지정한 호출 방식입니다. 일반적으로 0으로 설정됩니다.
);
int recv(
  SOCKET s,
  char FAR* buf,
  int len,
  int flags
);
 
send 함수는 연결된 바이트에 버퍼 내의 데이터를 보내고, 데이터를 보내는 실제 바이트 수를 되돌려주며,recv 함수는 상대방으로부터 데이터를 받아서 지정한 버퍼에 저장합니다.flag 매개 변수는 일반적으로 두 함수에서 0으로 설정됩니다.
 
막힘 모드에서send는 모든 데이터가 전송될 때까지 (또는 오류가 발생할 때까지) 라인의 실행을 막고,recv 함수는 버퍼가 지정한 크기까지 가능한 한 많은 현재 정보를 되돌려줍니다.
 
함수 실행 실패가 INVALID 로 반환됨SOCKET (-1), closesocket 함수를 호출해서 닫아야 합니다.오류가 발생하지 않으면 함수가 0을 반환하고 그렇지 않으면 SOCKET 를 반환합니다.ERROR.함수는 다음과 같이 사용됩니다.
int closesocket(
  __in SOCKET s//함수의 유일한 매개 변수는 닫을 소켓의 핸들입니다
);

 


4. 연결을 끊고 플러그인을 닫는다. (클라이언트가 데이터를 보냈을 때 shutdown 함수와SD SEND 매크로를 사용하여 플러그인을 보낼 수 있고 클라이언트는 서버 플러그인에서 데이터를 받아들일 수 있다)

iResult = shutdown(ConnectSocket, SD_SEND);

if (iResult == SOCKET_ERROR) {

    printf("shutdown failed: %d
", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } closesocket(ConnectSocket); WSACleanup();

 
전체 클라이언트 코드 포함:
#ifndef WIN32_LEAN_AND_MEAN

#define WIN32_LEAN_AND_MEAN

#endif

#include <windows.h>

#include <WinSock2.h>

#include <WS2tcpip.h>

#include <IPHlpApi.h>

#include <stdio.h>



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

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

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



#define DEFAULT_PORT "27015"

#define DeFAULT_BUFLEN 512



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

{

	WSADATA wsaData;

	int iResult;

	struct addrinfo *result = NULL, 

					*ptr = NULL,

					hints;



	char *sendbuf = "this is a test";

	char recvbuf[DeFAULT_BUFLEN];

	int recvbuflen = DeFAULT_BUFLEN;

	SOCKET ConnectSocket = INVALID_SOCKET;



	if (argc != 2)

	{

		printf("usage: %s server-name
", argv[0]); } // winsock iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != 0) { printf("WSAStartup failed: %d
", iResult); return 1; } ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; // iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result); if (iResult != 0) { printf("getaddrinfo failed: %d
", iResult); WSACleanup(); return 1; } // , for (ptr = result; ptr != NULL; ptr = ptr->ai_next) { // ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (ConnectSocket == INVALID_SOCKET) { printf("Error at socket(): %ld
", WSAGetLastError()); freeaddrinfo(result); WSACleanup(); return 1; } // iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); if (iResult == SOCKET_ERROR) { closesocket(ConnectSocket); ConnectSocket = INVALID_SOCKET; continue; } break; } // freeaddrinfo(result); if (ConnectSocket == INVALID_SOCKET) { printf("Unable to connect to server!
"); WSACleanup(); return 1; } // sendbuf iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf) + 1, 0); if (iResult == SOCKET_ERROR) { printf("send failed:%d
", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } printf("Byte Send:%ld
", iResult); // iResult = shutdown(ConnectSocket, SD_SEND); if (iResult == SOCKET_ERROR) { printf("shutdown faild: %d
", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } // do { iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0); if (iResult > 0) printf("Byte received: %d
", iResult); else if (iResult == 0) printf("connection closed
"); else printf("recv failed: %d
", WSACleanup()); } while (iResult > 0); // closesocket(ConnectSocket); WSACleanup(); return 0; }

본문 링크:http://www.bugcoding.com/entry/10

좋은 웹페이지 즐겨찾기