티스토리 뷰

책) TCP/IP 윈도우 소켓 프로그래밍

 

간단하게 멀티쓰레드로 send, recv만 해보았습니다.

 

Create Thread API 정리

HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes, // Security Descriptor
     보안설정 옵션, default = null;
     
    SIZE_T dwStackSize, // initial stack size
     생성시 요구되는 스택 공간 크기 default = 0;
     
    LPTHREAD_START_ROUTINE lpStartAddress, // thread function
    쓰레드가 실행할 함수의 포인터 (원형이 있음)
    
    LPVOID lpParameter, // thread argument
    함수의 인자
    
    DWORD dwCreateionFlags, // thread identifier
    바로 실행 or 대기 상태 default = 0;
    
    LPDWORD lpThreadId // thread identifier
    쓰레드 ID 값 저장
);

//DummyClient

#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>

#define MAXLINE 50
#define PORTNUM 5000

void err_quit(const char* msg) {
    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, WSAGetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf, 0, NULL);
    printf("[%s] %s", msg, (char*)lpMsgBuf);
    LocalFree(lpMsgBuf);
} 

DWORD WINAPI SendServer(LPVOID arg) {
    WSADATA wsaData;


    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("dlload error\n");
        return 1;
    }

    SOCKET sockfd;
    int addrlen;
    char buf[MAXLINE];
    struct sockaddr_in sockaddr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == INVALID_SOCKET)
    {
        printf("socket create error\n");
        return 1;
    }

    ZeroMemory(&sockaddr, sizeof(sockaddr));
    sockaddr.sin_family = AF_INET;
    sockaddr.sin_port = htons(PORTNUM);
    sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (::connect(sockfd, (SOCKADDR*)&sockaddr, sizeof(sockaddr))) err_quit("Connet");

    const char* testdata[] = {
        "안녕하세요",
        "반가워요",
        "오늘따라 할 이야기가 많을 것 같네요.",
        "저도 그렇네요"
    };

    for (int i = 0; i < 4; i++) {
        //데이터 입력
        int len = strlen(testdata[i]);
        strncpy(buf, testdata[i], len);

        //데이터 보내기(고정길이)
        int retVal = send(sockfd, (char*)&len, sizeof(int), 0);
        if (retVal == SOCKET_ERROR) {
            err_quit("Send");
            break;
        }

        //데이터 보내기(가변길이)
        retVal = send(sockfd, buf, len, 0);
        if (retVal == SOCKET_ERROR) {
            err_quit("Send");
            break;
        }
        //printf("[TCP 클라이언트] %d바이트를 보냈습니다.\n", retVal);

        retVal = recv(sockfd, buf, retVal, 0);
        if (retVal == SOCKET_ERROR) {
            err_quit("Recv");
            break;
        }
        buf[retVal] = '\0';
        printf("입력 받은 데이터 : %s\n", buf);
    }

    printf("소켓 통신 종료");
    closesocket(sockfd);
    WSACleanup();

    return 0;
}
int main()
{
    for (int i = 0; i < 10; i++) {
        HANDLE hThread = CreateThread(NULL, 0, SendServer, NULL, 0, NULL);
        if (hThread == NULL) return 1;
        CloseHandle(hThread);
    }
    while (1);
    return 0;
}

//DummyServer

#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>

#define MAXLINE 512
#define PORTNUM 5000

void err_quit(const char* msg) {
    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, WSAGetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf, 0, NULL);
    printf("[%s] %s", msg, (char*)lpMsgBuf);
    LocalFree(lpMsgBuf);
}

int recvn(SOCKET s, char* buf, int len, int flag) {
    int received;
    char* ptr = buf;
    int left = len;

    while (left > 0) {
        received = recv(s, ptr, left, flag);
        if (received == SOCKET_ERROR)
            return SOCKET_ERROR;
        else if (received == 0)
            break;
        left -= received;
        ptr += received;
    }
    return (len - left);
}

DWORD WINAPI ProcessClient(LPVOID arg) {
    SOCKET clientfd = (SOCKET)arg;
    SOCKADDR_IN clientaddr;
    int addrlen;
    int len;
    char buf[MAXLINE + 1];

    //클라 정보 얻기
    addrlen = sizeof(clientaddr);
    getpeername(clientfd, (SOCKADDR*)&clientaddr, &addrlen);

    while (1) {
        //데이터받기(고정길이)
        int retVal = recvn(clientfd, (char*)&len, sizeof(int), 0);
        if (retVal == SOCKET_ERROR) {
            err_quit("Recv");
            break;
        }
        else if (retVal == 0) break;

        //데이터받기(가변길이)
        retVal = recvn(clientfd, buf, len, 0);
        if (retVal == SOCKET_ERROR) {
            err_quit("Recv");
            break;
        }
        else if (retVal == 0) break;

        //받은 데이터 출력
        buf[retVal] = '\0';
        printf("[TCP/%s : %d] %s\n", inet_ntoa(clientaddr.sin_addr),
            ntohs(clientaddr.sin_port), buf);

        retVal = send(clientfd, buf, len, 0);
        if (retVal == SOCKET_ERROR) {
            err_quit("Send");
            break;
        }
    }
    closesocket(clientfd);
    printf("[TCP 서버] 클라이언트 종료 : IP  주소 = %s, 포트번호 = %d\n",
        inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

    return 0;
}

int main()
{
    WSADATA wsaData;
    SOCKET sockfd, clientfd;
    int addrlen;
    int len = 0;
    WSAEVENT sEvent;
    struct sockaddr_in sockaddr,clientaddr;
    HANDLE hThread;

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("dlload error\n");
        return 1;
    }

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == INVALID_SOCKET)
    {
        printf("socket create error\n");
        return 1;
    }

    sockaddr.sin_family = AF_INET;
    sockaddr.sin_port = htons(PORTNUM);
    sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (::bind(sockfd, (SOCKADDR*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) err_quit("Bind");
    if (::listen(sockfd, 5) == SOCKET_ERROR) err_quit("Listen");

    while (1)
    {
        addrlen = sizeof(clientaddr);
        clientfd = ::accept(sockfd, (SOCKADDR*)&clientaddr, &addrlen);
        if (clientfd == INVALID_SOCKET) {
            err_quit("Accept");
            break;
        }
        printf("[TCP서버] 클라이언트 접속 IP : %s %d\n", 
            inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
        
        hThread = CreateThread(NULL, 0, ProcessClient, (LPVOID)clientfd, 0, NULL);
        if (hThread == NULL) closesocket(clientfd);
        else CloseHandle(hThread);
    }

    closesocket(sockfd);
    WSACleanup();
    return 0;
}
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함