반응형
#include#include #include #define BUFSIZE 512 #define FD_SETSIZE 128 // 소켓 정보 저장을 위한 구조체 struct SOCKETINFO { SOCKET sock; char buf[BUFSIZE+1]; int recvbytes; int sendbytes; }; int nTotalSockets = 0; SOCKETINFO *SocketInfoArray[FD_SETSIZE]; // 소켓 관리 함수 BOOL AddSocketInfo(SOCKET sock); void RemoveSocketInfo(int nIndex); int FD_setadd(int add); // 오류 출력 함수 void err_quit(char *msg); void err_display(char *msg); int main(int argc, char* argv[]) { int retval; // 윈속 초기화 WSADATA wsa; if(WSAStartup(MAKEWORD(2,2), &wsa) != 0) return -1; // socket() SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0); if(listen_sock == INVALID_SOCKET) err_quit("socket()"); // bind() 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); retval = bind(listen_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr)); if(retval == SOCKET_ERROR) err_quit("bind()"); // listen() retval = listen(listen_sock, SOMAXCONN); if(retval == SOCKET_ERROR) err_quit("listen()"); // 넌블로킹 소켓으로 전환 u_long on = TRUE; retval = ioctlsocket(listen_sock, FIONBIO, &on); if(retval == SOCKET_ERROR) err_display("ioctlsocket()"); // 데이터 통신에 사용할 변수 FD_SET rset; FD_SET wset; SOCKET client_sock; SOCKADDR_IN clientaddr; int addrlen; while(1){ // 소켓 셋 초기화 FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(listen_sock, &rset); for(int i=0; i recvbytes > SocketInfoArray[i]->sendbytes) FD_SET(SocketInfoArray[i]->sock, &wset); else FD_SET(SocketInfoArray[i]->sock, &rset); } FD_setadd(FD_SETSIZE); // select() retval = select(0, &rset, &wset, NULL, NULL); if(retval == SOCKET_ERROR) err_quit("select()"); // 소켓 셋 검사(1): 클라이언트 접속 수용 if(FD_ISSET(listen_sock, &rset)){ addrlen = sizeof(clientaddr); client_sock = accept(listen_sock, (SOCKADDR *)&clientaddr, &addrlen); if(client_sock == INVALID_SOCKET){ if(WSAGetLastError() != WSAEWOULDBLOCK) err_display("accept()"); } else{ printf("[TCP 서버] 클라이언트 접속: IP 주소=%s, 포트 번호=%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); // 소켓 정보 추가 if(AddSocketInfo(client_sock) == FALSE){ printf("[TCP 서버] 클라이언트 접속을 해제합니다!\n"); closesocket(client_sock); } } } // 소켓 셋 검사(2): 데이터 통신 for(int i=0; i sock, &rset)){ // 데이터 받기 retval = recv(ptr->sock, ptr->buf, BUFSIZE, 0); if(retval == SOCKET_ERROR){ if(WSAGetLastError() != WSAEWOULDBLOCK){ err_display("recv()"); RemoveSocketInfo(i); } continue; } else if(retval == 0){ RemoveSocketInfo(i); continue; } ptr->recvbytes = retval; // 받은 데이터 출력 addrlen = sizeof(clientaddr); getpeername(ptr->sock, (SOCKADDR *)&clientaddr, &addrlen); ptr->buf[retval] = '\0'; printf("[TCP/%s:%d] %s\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), ptr->buf); } if(FD_ISSET(ptr->sock, &wset)){ // 데이터 보내기 retval = send(ptr->sock, ptr->buf + ptr->sendbytes, ptr->recvbytes - ptr->sendbytes, 0); if(retval == SOCKET_ERROR){ if(WSAGetLastError() != WSAEWOULDBLOCK){ err_display("send()"); RemoveSocketInfo(i); } continue; } ptr->sendbytes += retval; if(ptr->recvbytes == ptr->sendbytes){ ptr->recvbytes = ptr->sendbytes = 0; } } } } // 윈속 종료 WSACleanup(); return 0; } // 소켓 정보 추가 BOOL AddSocketInfo(SOCKET sock) { // FD_SETSIZE - 연결 대기 소켓 if(nTotalSockets >= (FD_SETSIZE-1)){ printf("[오류] 소켓 정보를 추가할 수 없습니다!\n"); return FALSE; } SOCKETINFO *ptr = new SOCKETINFO; if(ptr == NULL){ printf("[오류] 메모리가 부족합니다!\n"); return FALSE; } ptr->sock = sock; ptr->recvbytes = 0; ptr->sendbytes = 0; SocketInfoArray[nTotalSockets++] = ptr; return TRUE; } // 소켓 정보 삭제 void RemoveSocketInfo(int nIndex) { SOCKETINFO *ptr = SocketInfoArray[nIndex]; // 클라이언트 정보 얻기 SOCKADDR_IN clientaddr; int addrlen = sizeof(clientaddr); getpeername(ptr->sock, (SOCKADDR *)&clientaddr, &addrlen); printf("[TCP 서버] 클라이언트 종료: IP 주소=%s, 포트 번호=%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); closesocket(ptr->sock); delete ptr; for(int i=nIndex; i = FD_SETSIZE) { add++; } return add; }
'C, C++' 카테고리의 다른 글
[C++] molloc : 메모리 관리 new (0) | 2014.11.18 |
---|---|
[C++] C++ 의 구조와 C언어 개선사항 (0) | 2014.11.18 |
[C] 소켓 공부 (0) | 2014.11.18 |
[C] 소켓 공부하기!! (0) | 2014.11.18 |
[C] [자료구조] fib 함수를 사용해서 순환호출를 이해하기 (0) | 2014.11.18 |