int main(int argc, char *argv[]) { int retval; InitializeCriticalSection(&cs); // 윈속 초기화 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_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons(SERVERPORT); 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()"); // 더미(dummy) 이벤트 객체 생성 WSAEVENT hEvent = WSACreateEvent(); if(hEvent == WSA_INVALID_EVENT) err_quit("WSACreateEvent()"); EventArray[nTotalSockets++] = hEvent; // 스레드 생성 HANDLE hThread = CreateThread(NULL, 0, WorkerThread, NULL, 0, NULL); if(hThread == NULL) return 1; CloseHandle(hThread); // 데이터 통신에 사용할 변수 SOCKET client_sock; SOCKADDR_IN clientaddr; int addrlen; DWORD recvbytes, flags; while(1){ // accept() addrlen = sizeof(clientaddr); client_sock = accept(listen_sock, (SOCKADDR *)&clientaddr, &addrlen); if(client_sock == INVALID_SOCKET){ err_display("accept()"); break; } printf("\n[TCP 서버] 클라이언트 접속: IP 주소=%s, 포트 번호=%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); // 소켓 정보 추가 if(AddSocketInfo(client_sock) == FALSE){ closesocket(client_sock); printf("[TCP 서버] 클라이언트 종료: IP 주소=%s, 포트 번호=%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); continue; } // 비동기 입출력 시작 SOCKETINFO *ptr = SocketInfoArray[nTotalSockets-1]; flags = 0; retval = WSARecv(ptr->sock, &ptr->wsabuf, 1, &recvbytes, &flags, &ptr->overlapped, NULL); if(retval == SOCKET_ERROR){ if(WSAGetLastError() != WSA_IO_PENDING){ err_display("WSARecv()"); RemoveSocketInfo(nTotalSockets-1); continue; } } // 소켓의 개수(nTotalSockets) 변화를 알림 WSASetEvent(EventArray[0]); } // 윈속 종료 WSACleanup(); DeleteCriticalSection(&cs); return 0; }
//main int main() { int ret; //wsa WSADATA wsaData; ret = WSAStartup(MAKEWORD(2, 2), &wsaData); if (ret != 0) { return 1; } //socket SOCKET listenSock = socket(AF_INET, SOCK_STREAM, 0); if (listenSock == INVALID_SOCKET) { return 1; } //SOCKADDR SOCKADDR_IN serverAddr; ZeroMemory(&serverAddr, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(SERVER_PORT); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); //bind ret = bind(listenSock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)); if (ret == SOCKET_ERROR) { return 1; } //listen ret = listen(listenSock, SOMAXCONN); if (ret == SOCKET_ERROR) { return 1; } //non blocking u_long on = 1; ret = ioctlsocket(listenSock, FIONBIO, &on); if (ret == SOCKET_ERROR) { return 1; } //datas FD_SET readSet, writeSet; SOCKET clientSock; SOCKADDR_IN clientAddr; int addrLen = sizeof(clientAddr); int i; //main loop while (true) { //init fds FD_ZERO(&readSet); FD_ZERO(&writeSet); //add sock to fds FD_SET(listenSock, &readSet); for (i = 0; i < sockInfoNum; i++) { SockInfo* sockInfo = sockInfoArr[i]; if (sockInfo->recvBytes > sockInfo->sendBytes) { FD_SET(sockInfo->sock, &readSet); } else { FD_SET(sockInfo->sock, &writeSet); } } //select ret = select(0, &readSet, &writeSet, NULL, NULL); if (ret == SOCKET_ERROR) { break; } //fd loop if (FD_ISSET(listenSock, &readSet)) { clientSock = accept(listenSock, (SOCKADDR*)&clientAddr, &addrLen); if (clientSock == INVALID_SOCKET) { break; } AddSocketInfo(clientSock); } for (i = 0; i < sockInfoNum; i++) { SockInfo* sockInfo = sockInfoArr[i]; //is read if (FD_ISSET(sockInfo->sock, &readSet)) { //recv ret = recv(sockInfo->sock, sockInfo->buf, BUFFER_SIZE, 0); if (ret == SOCKET_ERROR) { RemoveSockInfoAt(i); continue; } sockInfo->sendBytes = ret; sockInfo->buf[ret] = '\0'; printf("%s \n", sockInfo->buf); } //is write if(FD_ISSET(sockInfo->sock, &writeSet)) { //send ret = send(sockInfo->sock, sockInfo->buf, sockInfo->sendBytes, 0); if (ret == SOCKET_ERROR) { RemoveSockInfoAt(i); continue; } } } //end fd loop } //end main loop //release datas closesocket(listenSock); WSACleanup(); return 0; } //main end
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_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons(SERVERPORT); 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 = 1; retval = ioctlsocket(listen_sock, FIONBIO, &on); if(retval == SOCKET_ERROR) err_display("ioctlsocket()"); // 데이터 통신에 사용할 변수 FD_SET rset, wset; SOCKET client_sock; SOCKADDR_IN clientaddr; int addrlen, i; while(1){ // 소켓 셋 초기화 FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(listen_sock, &rset); for(i=0; i<nTotalSockets; i++){ if(SocketInfoArray[i]->recvbytes > SocketInfoArray[i]->sendbytes) FD_SET(SocketInfoArray[i]->sock, &wset); else FD_SET(SocketInfoArray[i]->sock, &rset); } // 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){ err_display("accept()"); } else{ printf("\n[TCP 서버] 클라이언트 접속: IP 주소=%s, 포트 번호=%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); // 소켓 정보 추가 AddSocketInfo(client_sock); } } // 소켓 셋 검사(2): 데이터 통신 for(i=0; i<nTotalSockets; i++){ SOCKETINFO *ptr = SocketInfoArray[i]; if(FD_ISSET(ptr->sock, &rset)){ // 데이터 받기 retval = recv(ptr->sock, ptr->buf, BUFSIZE, 0); if(retval == SOCKET_ERROR){ 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){ err_display("send()"); RemoveSocketInfo(i); continue; } ptr->sendbytes += retval; if(ptr->recvbytes == ptr->sendbytes){ ptr->recvbytes = ptr->sendbytes = 0; } } } } // 윈속 종료 WSACleanup(); return 0; }