#include<winsock2.h>
#include<stdio.h>
#include<stdlib.h>
#define BUFSIZE 512
DWORD WINAPI ProcessClient(LPVOID arg);
///////////// 소켓 함수 오류 출력 후 종료 //////////////
void err_quit(char *msg)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, WSAGetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf, 0, NULL);
MessageBox(NULL, (LPCTSTR)lpMsgBuf, msg, MB_ICONERROR);
LocalFree(lpMsgBuf);
exit(-1);
}
///////////// 소켓 함수 오류 출력 ////////////////
void err_display(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, (LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
}
int main(int argc, char* argv[])
{
int retval;
/////////////// 윈속 초기화 //////////////
WSADATA wsa;
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0) //WSAStartup 성공:0, 실패:오류코드 이며, &wsa는 WSADATA타입 변수의 주소
//makeword는 주어진 상위, 하위 바이트를 조합하여 word 값을 반환합니다.
return -1;
/////////////// 1.socket /////////////
SOCKET listen_sock=socket(AF_INET,SOCK_STREAM,0); //socket(주소체계, 소켓 타입, 프로토콜)
if(listen_sock==INVALID_SOCKET) err_quit("socket()"); //listen_sock의 리턴값이 INVALID_SOCKET이면 err_quit함수 호출
/////////////////// 2.bind /////////////////////
SOCKADDR_IN serveraddr; /* struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
*/
ZeroMemory(&serveraddr,sizeof(serveraddr)); //ZeroMemory는 구조체나 변수를 초기화, serveraddr의 구조체 변수를 초기화
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(9090); //htons는 host byte order를 network byte order로 Port정보의 바이트 순서변경
serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
retval=bind(listen_sock, (SOCKADDR*)&serveraddr, sizeof(serveraddr)); /* int bind (
SOCKET s,
const struct sockaddr* name,
int namelen
); 성공:0, 실패:SOCKET_ERROR
*/ //bind()는 서버의 지역IP주소와 지역 포트 번호를 결정된다. 성공:0, 실패:SOCKET_ERROR
//listen_sock, ip주소, 포트번호
if(retval==SOCKET_ERROR) err_quit("bind()"); //int형 변수retval가 SOCKET_ERROR 이면 err_quit함수 호출
//////////////////// 3.listen ///////////////////
retval=listen(listen_sock, SOMAXCONN); /* listen(
SOCKET s,
int backlog); 성공:0, 실패:SOCKET_ERROR
*/
if(retval==SOCKET_ERROR) err_quit("listen()"); //retval에 SOCKET_ERROR이면 err_quit()함수 실행
// 데이터 통신에 사용할 변수
SOCKET client_sock;
SOCKADDR_IN clientaddr;
int addrlen;
DWORD lpThread = 0;
while(1){
//////////////////// 4.accept //////////////////
//클라이언트 접속 수용 1
addrlen=sizeof(clientaddr);
client_sock=accept(listen_sock, (SOCKADDR*)&clientaddr, &addrlen); /* SOCKET accept(
SOCKET s,
struct sockaddr* addr,
int* addrlen
); 성공:새로운 소켓, 실패:INVALID_SOCKET
*/
if(client_sock==INVALID_SOCKET){ //client_sock이 INVALID_SOCKET이면 err_display()함수 실행
err_display("accept()");
continue; //다시 while(1)문으로
}
//스레드 생성 2
CreateThread(NULL, 0, ProcessClient, (LPVOID)client_sock, 0, &lpThread);
/* HANDLE CreateThread (
LPSECURITY_ATTRIBUTES lpThreadAttributes, // NULL
SIZE_T dwStackSize, // 0
LPTHREAD_START_ROUTINE lpStartAddress, // 스레드 함수
LPVOID lpParameter, // 스레드 함수 인자
DWORD dwCreationFlags, // 0 또는 CREATE_SUSPENDED
LPDWORD lpThreadId // 스레드 ID
) ; 성공: 스레드 핸들, 실패: NULL
*/
}
/////////////// 7.closesocket() ////////////////
closesocket(listen_sock); //listen_sock 소켓을 닫음
// 윈속 종료
WSACleanup(); //성공:0, 실패:SOCKET_ERROR
return 0;
}
DWORD WINAPI ProcessClient(LPVOID arg)
{
SOCKADDR_IN clientaddr;
int addrlen;
int retval;
char buf[BUFSIZE+1];
//전달된 소켓 3
SOCKET client_sock = (SOCKET)arg;
//클라이언트 정보 얻기 4
addrlen = sizeof(clientaddr);
getpeername(client_sock, (SOCKADDR *)&clientaddr, &addrlen);
printf("\n[TCP 서버] 클라이언트 접속: IP 주소=%s, 포트 번호=%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
//클라이언트와 데이터 통신 5
while(1){
////////////////// 5.recv ///////////////////
retval=recv(client_sock, buf, BUFSIZE, 0); /* int recv (
SOCKET s,
char* buf,
int len,
int flags
); 성공: 받은 바이트 수 또는 0(연결 종료시), 실패: SOCKET_ERROR
수신 버퍼에 도착한 데이터를 애플리케이션 버퍼로 복사
*/
if(retval==SOCKET_ERROR){
err_display("recv()");
break;
}
else if(retval==0)
break;
//받은 데이터 출력
buf[retval] = '\0'; //buf[retval]를 \0 으로 초기화
printf("[TCP/%s:%d] %s\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), buf);
/////////////// 6.send ////////////////
retval = send(client_sock, buf, retval, 0); /* int send (
SOCKET s,
const char* buf,
int len,
int flags
); 성공: 보낸 바이트 수, 실패: SOCKET_ERROR
애플리케이션 데이터를 송신 버퍼에 복사함으로써 궁극적으로 하부 프로토콜에 의해 데이터가 전송
*/
if(retval == SOCKET_ERROR){
err_display("send()");
break;
}
}
// closesocket()
closesocket(client_sock);
return 0;
}
'시스템 프로그래밍 > 소켓프로그래밍' 카테고리의 다른 글
| UDP Server Client (0) | 2009/04/27 |
|---|---|
| Visual C++ 1대1 스레드를 이용한 Server와 Client (0) | 2009/04/24 |
| 스레드를 이용한 Server (0) | 2009/04/23 |



Prev
