하나의 서버에 두개 이상의 클라이언트가 접속될 경우 교착상태에 빠진다.
이를 멀티스레드로 해결해본다. (해결방법은 여러가지)
어제 TCP 서버/클라이언트를 만들었는데, 거기서 스레드를 추가하는 거다.
#include <Winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFSIZE 512
DWORD WINAPI ProcessClient(LPVOID arg)
{
SOCKET client_sock = (SOCKET)arg;
char buf[BUFSIZE+1];
SOCKADDR_IN clientaddr;
int addrlen;
int retval;
addrlen = sizeof(clientaddr);
getpeername(client_sock, (SOCKADDR*)&clientaddr, &addrlen);
// 클라이언트와 데이터 통신
while(1)
{
retval = recv(client_sock, buf, BUFSIZE, 0);
if (retval == SOCKET_ERROR)
{
printf("수신() 에러\n");
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(client_sock, buf, retval, 0);
if (retval == SOCKET_ERROR)
{
printf("송신() 에러\n");
break;
}
}
// closesocket()
closesocket(client_sock);
printf("TCP 서버, 클라이언트 종료 : IP 주소 = %s, 포트번호 = %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
return 0;
}
int main(int argc, char* argv[])
{
if(argc != 2)
{
fprintf(stderr, "Usage : %s, 포트사용\n", argv[0]);
return -1;
}
// 윈속초기화
WSADATA wsa;
if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return -1;
// 리턴 값 저장시킬 변수
int return_val;
// socket()
SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if(listen_sock == INVALID_SOCKET) printf("소켓() 에러염\n");
long port;
port = atol(argv[1]);
// bind()
SOCKADDR_IN serveraddr;
ZeroMemory(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(port);
/*
XP 이전에는 INADDR_ANY의 값에 빈 스트링을 넘겨줄 경우 INADDR_ANY로 세팅되었지만,
2003 이후로는 INADDR_NONE의 에러값을 넘겨준다, INADDR_NONE은 IP대역이 A.B.C.D 중 하나라도 255를 초과 할 경우 세팅
INADDR_ANY는 어느 주소로 접속하던 접속을 받아들인다.
*/
serveraddr.sin_addr.s_addr = htons(INADDR_ANY);
return_val = bind(listen_sock, (SOCKADDR*)&serveraddr, sizeof(serveraddr)); // connect가 아니라 bind
if(return_val == SOCKET_ERROR) printf("바인딩() 에러염\n");
// listen()
return_val = listen(listen_sock, SOMAXCONN);
if(return_val == SOCKET_ERROR) printf("리슨() 에러염\n");
// 데이터 통신에 사용할 변수
SOCKET client_sock;
SOCKADDR_IN clientaddr;
char buf[BUFSIZE + 1];
int addrlen;
HANDLE hThread; // 스레드 핸들
DWORD ThreadID; // 스레드 아이디
// 서버와 데이터 통신
while(1)
{
// accept()
addrlen = sizeof(clientaddr);
client_sock = accept(listen_sock, (SOCKADDR*)&clientaddr, &addrlen);
if (client_sock == INVALID_SOCKET){
printf("accept() 에러\n");
continue;
}
printf ("TCP 서버, 클라이언트 접속 : IP 주소 = %s, 포트번호 = %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
hThread = CreateThread(NULL, 0, ProcessClient, (LPVOID)client_sock, 0, &ThreadID);
if(hThread == NULL)
{
printf("스레드 생성 실패ㅠㅠ\n");
}
else
{
CloseHandle(hThread);
}
}
closesocket(listen_sock);
// 윈속 종료
WSACleanup();
return 0;
}
'Web, Network Programming > Socket' 카테고리의 다른 글
TCP, UDP의 특징 비교 (0) | 2014.11.07 |
---|---|
TCP 서버/클라이언트 (0) | 2014.06.16 |
도메인 네임 서버 (0) | 2014.06.16 |
바이트 정렬 (0) | 2014.05.29 |
Socket 생성 (0) | 2014.05.29 |