Select()를 이용해 채팅 서버-클라이언트(Standalone방식?) 프로그래밍 중 질문드립니다.
글쓴이: theageha / 작성시간: 금, 2008/05/09 - 5:37오후
/* Student ID : 20031943 Name : 박성진 */ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/stat.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXSOCK 100 #define MAXLINE 1000 int tcpSockets[MAXSOCK]; // List of sockets int connCount=0; // connection count void removeClient(int i); int getmax(int k); void error_handling(char *command); int main(int argc, char **argv) { int tcpServ_sock; // a TCP server Socket int udpServ_sock; // a UDP server Socket int tcpRcv_sock; int udpCnt_sock; int tcpCnt_sock; fd_set reads, temps; int fd_max, fd, tcpReq; char msg[MAXLINE]; char rcvmsg[MAXLINE]; char command[MAXLINE]; char udpReq_msg[MAXLINE]; char udpRcv_msg[MAXLINE]; char tcpReq_msg[MAXLINE]; char closemsg[MAXLINE]; char *comm, *reqhost, *udpPort, *tcpPort, *host; struct sockaddr_in tcpServ_addr; struct sockaddr_in udpServ_addr; struct sockaddr_in tcpReq_addr; struct sockaddr_in udpReq_addr; int tcp_byte_read, udpReq_addr_size, udp_byte_read, tcpReq_addr_size, close_byte_read, rcv_byte_read; int i,j,k, testn; if(argc != 4){ printf("Usage : %s <tcpport> <udpport> <userid>\n", argv[0]); exit(1); } printf("Student ID :20031943\n"); printf("Name : Park Sung-jin\n"); if((tcpServ_sock=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0) error_handling("TCP server socket opening is failed!\n"); if((udpServ_sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))<0) error_handling("UDP server socket opening is failed!\n"); memset(&tcpServ_addr, 0, sizeof(tcpServ_addr)); tcpServ_addr.sin_family=AF_INET; tcpServ_addr.sin_addr.s_addr=htonl(INADDR_ANY); // need modifying !!!!!!!!!!! tcpServ_addr.sin_port = htons(atoi(argv[1])); if(bind(tcpServ_sock, (struct sockaddr*)&tcpServ_addr, sizeof(tcpServ_addr))<0) error_handling("TCP server binding is failed!\n"); if(listen(tcpServ_sock, MAXLINE)<0) error_handling("listening is failed!\n"); FD_ZERO(&reads); FD_SET(fileno(stdin), &reads); FD_SET(tcpServ_sock, &reads); FD_SET(udpServ_sock, &reads); fd_max = udpServ_sock; printf("%s>\n", argv[3]); while(1){ int nfound; temps = reads; <span>fd_max=getmax(tcpServ_sock);</span> if(nfound = select(fd_max+1, &temps, 0, 0, NULL)<0) error_handling("Select is failed!\n"); for(i=0; i<connCount; i++) //check; FD_SET(tcpSockets[i], &temps); if(FD_ISSET(fileno(stdin), &temps)) { FD_CLR(fileno(stdin), &temps); fgets(command, MAXLINE, stdin); comm=strtok(command, " "); reqhost=strtok(NULL, " "); udpPort=strtok(NULL, "\n"); if(strncmp(comm, "@c", 2)==0){ if((udpCnt_sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))<0) error_handling("UDP Client socket opening is failed!\n"); sprintf(udpReq_msg, "Connect %s", argv[1]); //creat udp message sendto(udpCnt_sock, udpReq_msg, strlen(udpReq_msg), 0,(struct sockaddr*)&udpServ_sock, sizeof(udpServ_addr)); close(udpCnt_sock); }/* else if(strncmp(comm, "@q", 2)==0){ if((udpCnt_sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))<0) error_handling("UDP Client socket opening is failed!\n"); memset(&tcpServ_addr, 0, sizeof(tcpServ_addr)); tcpServ_addr.sin_family=AF_INET; tcpServ_addr.sin_addr.s_addr=htonl(INADDR_ANY); // need modifying !!!!!!!!!!! tcpServ_addr.sin_port = htons(atoi(argv[2])); sprintf(udpReq_msg, "@q"); //creat udp message sendto(udpCnt_sock, udpReq_msg, strlen(udpReq_msg), 0,(struct sockaddr*)&tcpServ_sock, sizeof(tcpServ_addr)); close(udpCnt_sock); exit(1); } */ printf("%s>", argv[3]); } else if(FD_ISSET(udpServ_sock, &temps)){ FD_CLR(udpServ_sock, &temps); printf("udpServ check"); memset(&udpServ_addr, 0, sizeof(udpServ_addr)); udpServ_addr.sin_family=AF_INET; udpServ_addr.sin_addr.s_addr=htonl(INADDR_ANY); // need modifying !!!!!!!!!!! udpServ_addr.sin_port = htons(atoi(argv[2])); if(bind(udpServ_sock, (struct sockaddr*)&udpServ_addr, sizeof(udpServ_addr))<0) error_handling("UDP server binding is failed!\n"); // NEED TO IMPLEMENT // Other user sent a connection request via UDP message udpReq_addr_size=sizeof(udpReq_addr); udp_byte_read=recvfrom(udpServ_sock, udpRcv_msg, MAXLINE, 0, (struct sockaddr*)&udpReq_addr, &udpReq_addr_size); strtok(udpRcv_msg, " "); host=strtok(NULL, " "); tcpPort=strtok(NULL, "\n"); memset(&tcpServ_addr, 0, sizeof(tcpServ_addr)); tcpServ_addr.sin_family=AF_INET; tcpServ_addr.sin_addr.s_addr=htonl(atoi(host)); // need modifying !!!!!!!!!!! tcpServ_addr.sin_port = htons(atoi(tcpPort)); if((tcpCnt_sock=socket(PF_INET, SOCK_STREAM,0))<0) error_handling("TCP client socket opening is failed!\n"); if(connect(tcpCnt_sock, (struct sockaddr*)&tcpServ_addr, sizeof(tcpServ_addr))<0) error_handling("TCP connection is failed\n"); } else if(FD_ISSET(tcpServ_sock, &temps)) { FD_CLR(tcpServ_sock, &temps); tcpReq_addr_size=sizeof(tcpReq_addr); if(tcpRcv_sock=accept(tcpServ_sock, (struct sockaddr*)&tcpReq_addr, &tcpReq_addr_size)<0) error_handling("Accept is failed\n"); tcpSockets[connCount]=tcpRcv_sock; connCount++; // NEED TO IMPLEMENT // Other user requested a TCP connection } // for messages from other users else if(FD_ISSET(tcpCnt_sock, &temps)){ FD_CLR(tcpCnt_sock, &temps); if((rcv_byte_read = recv(tcpCnt_sock,rcvmsg,MAXLINE, 0 ))<0) error_handling("recieve error\n"); rcvmsg[rcv_byte_read] = '\0'; printf("%s : %s\n", argv[3], rcvmsg); } <span>for (fd = 0; fd <= fd_max ; fd++) {</span> /* look for other sockets that have data available */ if (FD_ISSET(fd, &temps)) { FD_CLR(fd, &temps); // NEED TO IMPLEMENT // read the message from the socket fd if((tcp_byte_read = recv(tcpSockets[fd],msg,MAXLINE, 0 )) <= 0) { removeClient(i); continue; } if(strstr(msg,"@q") != NULL) { sprintf(closemsg,"Connection Closed %d\n", fd); for(k=0;k<connCount;k++); send(tcpSockets[k], closemsg, strlen(closemsg), 0); removeClient(i); continue; } /* 모든 채팅 참가자에게 메시지 방송 */ msg[tcp_byte_read] = '\0'; for(j = 0; j < connCount; j++) send(tcpSockets[j],msg,tcp_byte_read,0); printf("%s\n",msg); // write the message to other neighbors // print the message on the screen } } }//while End close(tcpServ_sock); close(udpServ_sock); }//main End int getmax(int k) { int max = k; int r; for(r = 0; r < connCount ; r++) /* 채팅 참가자 수만큼 소켓 배열 탐색 */ if(tcpSockets[r] > max) max = tcpSockets[r]; return max; } void error_handling(char *command){ fputs(command, stderr); fputc('\n', stderr); exit(1); } void removeClient(int i) /* i번째 참가자 탈퇴 */ { close(tcpSockets[i]); /* 해당 소켓 닫기 */ if(i != connCount-1) tcpSockets[i] = tcpSockets[connCount -1]; /* i번째 참가자와 맨 마지말 참가장의 위치 switch*/ connCount --; /* 채팅 참가자 수 1명 줄이기 */ }
여기저기서 짜집기하구, 급하게 만들어서 보시기 좀 불편하실 수도 있겠네요;;
1. 중간에 fd_max 저렇게 해도 되나요? max=udpServ_sock; 이후에 fd_max=getMax(tcpServ_sock) 하게 되면 값이 바뀌지 않나요?
2. main문 맨 아래 for 루프에서 왜 fd=0 부터인지 모르겠습니다. 파일디스크립터가 3번부터 부여되는 것으로 알고 있는데..
게다가 이미 3번tcpServer, 4번udpServer 로 부여가 되었을텐데, 그럼 5번부터 돌아야하는거 아닌가요?
그래서 5번-최초의 tcpClient 사용자가 되겠죠-에 출력할 내용이 있으면 출력!;;
3.실제로 컴파일 해보면 udp클라이언트에서 udp 서버로 요청하는 부분부터 안넘어가집니다.
토큰으로 명령어 다 짤라내서 요청 메세지를 만들어 내는데, 그 메세지가 udpServer쪽으로 넘어갔는지 확인할 방법이 없네요.ㅠ
제가 코딩을 잘못한 것일까요?ㅠ
Forums:
1. getmax 함수가
1. getmax 함수가 어떻게 되어 있는지 모르겠지만 현재 설정된 파일 디스크립트 보다 큰 값이
들어올 경우에 업데이트 해주는거 같으니 상관없을 거 같네요. 당연히 connection이 추가 되서
파일 디스크립트가 추가 되면 fd_max 도 증가 시켜줘야 겠지요..
2. fd 가 0번 부터 되는건 코드 보시면 아실수 있으실 텐데요.
보시면 0번도 세팅합니다. (0: input, 1: output, 2: error)
자세힌 모르겠으나 사용자가 입력하는 명령어에 대해서도 처리를 해줄려고 저리 했나 보네요.
3. udp는 connectionless 였던가 아무튼 tcp 랑 다르게 보내면 땡입니다. 수신측에서 잘 받았는지
안받았는지.. 신경 안쓰죠..
허접한 답변이지만 도움이 됬으면 하네요.. 그럼 수고하십시오.^^;;
앗 감사합니다.^^
설명해주신 부분은 이해가 되었습니다.
그래서 sendto가 리턴하는 것을 이용해서 메세지가 날라갔는지 확인해보니 -1, 즉 실패하더라구요;;
왜그런지 모르겠습니다.ㅠㅠ 혹시 알고 계시면 답변 부탁드립니다.
혹시 몰라서 주소 구조체 셋팅을 다시 했습니다. 그런데도 안돼네요..
----------------------------------------------------------------------------
삼인행 필유아사언(三人行 必有我師焉) - 세 사람이 길을 가면 그 중에 반드시 스승이 있다.
----------------------------------------------------------------------------
삼인행 필유아사언(三人行 必有我師焉) - 세 사람이 길을 가면 그 중에 반드시 스승이 있다.
크아아악 누가 좀 도와주세요..제발..ㅠㅠ
진짜...이 부분 왜 안되는지도저히 모르겠어요..ㅠㅠ
윗쪽에서 이미 udpServ_addr에 대한 주소 구조체를 초기화 시켜줘서 그런걸까요?
혹시 몰라서 udpServ2_addr을 따로 만들고, 서버소켓도 하나 더 만들어서 테스트 했는데도 안돼요..
계속 sending error 메시지만 나오구.....udp는 서버안키고 그냥 전송해도 전송까지는 되어야 되는거 아닌가요?
도착하는걸 확인안한다고 했으니...전송까지라도 되야되는데..ㅠ
----------------------------------------------------------------------------
삼인행 필유아사언(三人行 必有我師焉) - 세 사람이 길을 가면 그 중에 반드시 스승이 있다.
----------------------------------------------------------------------------
삼인행 필유아사언(三人行 必有我師焉) - 세 사람이 길을 가면 그 중에 반드시 스승이 있다.
댓글 달기