// 0406.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <winsock2.h> //windows.h보다 먼저 선언해야함
#include <windows.h>
#include <process.h>
#include <stdlib.h>
#include <iostream>

#define BUFSIZE 512

SOCKET client_sock[2];
int client_num=0;

unsigned int WINAPI ServerProc(LPVOID lpParam);

unsigned int WINAPI ClientContorl01(LPVOID lpParam); //소켓 0번과 통신
unsigned int WINAPI ClientContorl02(LPVOID lpParam); //소켓 1번과 통신
unsigned int WINAPI ClientSendProc(LPVOID lpParam); //소켓 1번과 통신

int main(int argc, char* argv[])
{
    DWORD dwID;
   
    HANDLE h = (HANDLE)_beginthreadex(NULL, 0, ServerProc, NULL, 0, (unsigned *)&dwID); //스레드 생성
   
    WaitForSingleObject(h,INFINITE);  //스레드 종료를 기다림
   
    printf("Main Thread 종료\n");
   
    CloseHandle(h);           //핸들을 반환
   
    return 0;
}

unsigned int WINAPI ClientSendProc(LPVOID lpParam)//클라이언트 접속시 데이타 처리부분
{
    char buf[BUFSIZE+1];
    int len;
   
    while(1)
    {
        ZeroMemory(buf,sizeof(buf));//보낼 데이타를 담는 버퍼 초기화
        printf("\n send data:");        //사용자로 부터 보낼 데이타를
        //입력 하라는  메시지 출력
       
        if(fgets(buf,BUFSIZE+1,stdin)==NULL)// 사용자의 입력을 받음
            break;//입력 받기에 실패했다면 반복문을 빠져나감
       
        len=strlen(buf);//입력 받은 문자열의 길이를 저장
        if(len-1==0)    //입력 받은 문자가 없다면
        {
            printf("통신을 종료합니다.\n");//통신종료 메시지 출력
            break;                                  //반복문 빠져나감
        }
        else                                         //입력받은 데이타의 마지막에 0을 넣어줌
            buf[len]='\0';                      //출력시 에러 방지
       
      
        for(int num=0; num<client_num; num++)
        {
            send(client_sock[num],buf,BUFSIZE,0);
        }
    }
   
    return 0;
}

unsigned int WINAPI ClientContorl02(LPVOID lpParam)//클라이언트 접속시 데이타 처리부분
{  
    SOCKET client_sock01 = (SOCKET)lpParam;
    char buf[BUFSIZE+1];
    SOCKADDR_IN clientaddr;
    int addrlen;
    int retval;
   
    // client 정보 얻기
    addrlen = sizeof(clientaddr);
    // client소켓을 통해서 주소 정보를 얻어온다.
    getpeername(client_sock01,(SOCKADDR *)&clientaddr,&addrlen);
   
    while(1)
    {
        //데이타 받기
        retval = recv(client_sock01, buf, BUFSIZE, 0 );
        if(retval == SOCKET_ERROR)
        {
            printf("데이타 받기 실패!");
            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);
       
         for(int num=0; num<client_num; num++)
        {
            send(client_sock[num],buf,retval,0);
        }

    }
   
    closesocket(client_sock01);
    printf("ClientContorl 종료 [TCP서버]:IP 주소:%s, 포트번호=%d\n"\
        ,inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
   
    return 0;
}

unsigned int WINAPI ClientContorl01(LPVOID lpParam)//클라이언트 접속시 데이타 처리부분
{  
   SOCKET client_sock01 = (SOCKET)lpParam;
    char buf[BUFSIZE+1];
    SOCKADDR_IN clientaddr;
    int addrlen;
    int retval;
   
    // client 정보 얻기
    addrlen = sizeof(clientaddr);
    // client소켓을 통해서 주소 정보를 얻어온다.
    getpeername(client_sock01,(SOCKADDR *)&clientaddr,&addrlen);
   
    while(1)
    {
        //데이타 받기
        retval = recv(client_sock01, buf, BUFSIZE, 0 );
        if(retval == SOCKET_ERROR)
        {
            printf("데이타 받기 실패!");
            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);
       
         for(int num=0; num<client_num; num++)
        {
            send(client_sock[num],buf,retval,0);
        }

    }
   
    closesocket(client_sock01);
    printf("ClientContorl 종료 [TCP서버]:IP 주소:%s, 포트번호=%d\n"\
        ,inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
   
    return 0;
}


unsigned int WINAPI ServerProc(LPVOID lpParam)//클라이언트 접속시 데이타 처리부분
{  
   
    WSADATA wsa;
    int retval;
    //윈속 초기화
    if(WSAStartup(MAKEWORD(2,2),&wsa) !=0)
        return -1;
   
    SOCKET listen_sock = socket(AF_INET,SOCK_STREAM,0);
   
    if(listen_sock == INVALID_SOCKET)
        printf("소켓 초기화 실패\n");
   
   
    SOCKADDR_IN serveraddr;
   
    ZeroMemory(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family= AF_INET;
    serveraddr.sin_port=htons(9000);
    serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
   
    //bind 서버의 지역 IP주소와 지역 포트번호를 결정
    //(클라이언트의 접속을 수용할 소켓,이변수늬 주소와 지역포트 번호로 초기화 시킴,소켓주소 구조체변수의 길이)
    retval=bind(listen_sock,(SOCKADDR*)&serveraddr,sizeof(serveraddr));
    if(retval==SOCKET_ERROR)
        printf("bind error\n");
   
    //listen
    //client의 접속을 받아들일수 있는 상태로 포트 상태를 변경한다.
    retval=listen(listen_sock,SOMAXCONN);
    if(retval==SOCKET_ERROR)
        printf("listen error\n");
   
   
   
   
    SOCKADDR_IN clientaddr;
    int addrlen;
    HANDLE hThread01,hThread02;
    DWORD THreadID;
   
    //accept()
    addrlen = sizeof(clientaddr);
    //클라이언트에서 접근을 하면 연결을 허락해준다.
    //(소켓 서버, 클라이언트의 주소(sockaddr 타입), 클라이언트 주소의사이즈)
   
    while(client_num<2)
    {
        printf("client 접속대기\n");
       
        client_sock[client_num] = accept(listen_sock,(SOCKADDR *)&clientaddr,&addrlen);
        if(client_sock[client_num] ==INVALID_SOCKET)
        {
            printf("accept error\n");
        }
        Sleep(1);
       
        printf("[TCP 서버]클라이언트 접속: IP 주소=%s, 포트번호 %d\n",\
            inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
       
       
        switch(client_num)
        {
        case 0:
            hThread01 = (HANDLE)_beginthreadex(NULL, 0,  ClientSendProc,(LPVOID)client_sock[client_num], 0, (unsigned *)&THreadID); //스레드 생성 
            hThread01 = (HANDLE)_beginthreadex(NULL, 0, ClientContorl01,(LPVOID)client_sock[client_num], 0, (unsigned *)&THreadID); //스레드 생성
            if(hThread01==NULL)
                printf("Client Thread Error\n");          
            break;
        case 1:
            hThread02 = (HANDLE)_beginthreadex(NULL, 0, ClientContorl02,(LPVOID)client_sock[client_num], 0, (unsigned *)&THreadID); //스레드 생성
            if(hThread02==NULL)
                printf("Client Thread Error\n");
            break;
        default:
            printf("잘못된 대기입니다.\n");
            return 0;
        }
       
        client_num++;
    }
   
   
    WaitForSingleObject(hThread01,INFINITE);  //스레드 종료를 기다림
    WaitForSingleObject(hThread02,INFINITE);  //스레드 종료를 기다림
   
    printf("server thread 종료\n");
    CloseHandle(hThread01);
    CloseHandle(hThread02);
    closesocket(listen_sock);
    WSACleanup();          //윈속 종료
    return 0;
}

Posted by 지화명이
,