select를 이용한 채팅 프로그램 질문!!
글쓴이: jwy22 / 작성시간: 화, 2004/03/30 - 3:26오후
안녕하세요.
아래 코드는 제가 짠 select를 이용한 채팅프로그램입니다.
컴파일은 이상 없는데...
select 부분이 안돌아 가는거 같습니다.
뭐가 잘못된것인지...
다충 클라이언트 채팅을 만들려고 하는데...이부분에서 걸려서 못하고 있습니다.
많은 분들의 도움 부탁드립니다.
#include <stdio.h> #include <strings.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/uio.h> #include <sys/time.h> #include <unistd.h> #include <sys/select.h> #include <signal.h> #include <sys/wait.h> #include <stdlib.h> #define PORT_NUM 5678 #define IPADDR "192.168.0.1" main(){ /* 변수정의 */ int Sock_Num; //소켓번호 char str_Buf[512]; //버퍼 int acc_Sock, state, Server_len; int max_Client = 10;//최대 접속 클라이언트수 struct sockaddr_in Server_Addr; //주소를 만든다. memset(&Server_Addr, '0', sizeof(Server_Addr)); //구조체를 0으로 초기화 Server_Addr.sin_family = AF_INET; //주소 체계 Server_Addr.sin_port = htons(PORT_NUM);//16비트 포트 번호 Server_Addr.sin_addr.s_addr = inet_addr(IPADDR);//32비트 IP 주소 struct timeval Wait_time; fd_set read_set; //파일 지시자의 그룹을 fd_set 비트배열에 집어 넣음 fd_set write_set; if((Sock_Num = socket(AF_INET, SOCK_STREAM, 0)) < 0){ // 소켓을 생성한다. printf("Sock error\n"); exit(0); } if((bind(Sock_Num, (struct sockaddr *)&Server_Addr, sizeof(Server_Addr))) < 0){ //생성된 소켓을 바인딩 한다. printf("bind error\n"); exit(0); } if(listen(Sock_Num, 5) < 0){ // 연결을 기다린다. printf("listen error\n"); exit(0); } FD_ZERO(&read_set); FD_SET(Sock_Num, &read_set); printf("Waiting Clinet Connect....\n"); int z; printf("2222\n"); for(;;){ //서버 반복문 FD_ZERO(&write_set); for(z=0; z < Sock_Num + 1; ++z){ if(FD_ISSET(z, &read_set)) FD_SET(z, &write_set); } Wait_time.tv_sec = 0; Wait_time.tv_usec = 10000; state = select(Sock_Num + 1 , &write_set, 0, 0, &Wait_time ); if(state = 0){ printf("Time Out\n"); exit(0); } else if (state < 0){ printf("select error\n"); exit(0); } printf("select ok\n"); // Wait_time 간격으로 연결요청을 체크한다. if(FD_ISSET(Sock_Num, &write_set)){ //Sock_Num이 read_socks집합에 있을경우, 연결요청이 있는 경우. Server_len=sizeof(Server_Addr); if(acc_Sock = accept(Sock_Num, (struct sockaddr *)&Server_Addr, &Server_len) < 0){ // 연결요청을 수락한다. printf("accept error\n"); exit(0); } printf("Client accept\n"); if(acc_Sock >= max_Client){ //클라이언트수가 최대수를 초과했는지 검사 close(acc_Sock); printf("MAX CLIENT\n"); } if(read(Sock_Num, str_Buf, sizeof(str_Buf))<0){ printf("error read1"); exit(0); } } //end of if(FD_ISSET) if(read(acc_Sock, str_Buf, sizeof(str_Buf)) < 0 ){ printf("read error\n"); exit(0); } printf("return : %s\n",str_Buf); FD_SET(acc_Sock, &read_set); } //End of for close(Sock_Num); // 소켓을 닫는다. } // End of main()
Forums:
[code:1] if(state = 0){
이 부분에서 state = 0이 잘못 됬네요
그리고 select에서 timeout이 나면 종료 할것이
아니라 다시 select를 시작해야 하지 않을까요?
울랄라~ 호기심 천국~!!
http://www.ezdoum.com
[quote="choissi"][code:1] if(st
답변 감사합니다.
님의 답변보구 아래처럼 소스를 수정했습니다.
그래도 서버가 응답이 없네요.
멀 잘못짠건지...select 부분은 이상이 없는건가요??
내손안에는 아직 비장의 무기가 남아 있다.
그것은 희망이다.
-나폴레옹-
state =0 도 state == 0
state =0 도 state == 0
울랄라~ 호기심 천국~!!
http://www.ezdoum.com
먼저 답변 감사합니다.select 부분을 아래와 같이 고치고 [c
먼저 답변 감사합니다.
select 부분을 아래와 같이 고치고
"printf("Time out\n");"을 삽입해서 관찰해 보았습니다.
그랬더니 출력결과는
Time out 메시지가 나오다가 클라이언트가 붙은 후에 저러고 가만히 있습니다.
멀 잘못한건지...모르겠습니다. :cry:
내손안에는 아직 비장의 무기가 남아 있다.
그것은 희망이다.
-나폴레옹-
소스를 보니...read() 부분 전부가 readable 한지 확인
소스를 보니...
read() 부분 전부가 readable 한지 확인 하는곳없이 무조건 read()를 하는군요.
그럼 당연히 server로 무언가 write()가 오기 전에는 계속 block된 상태가 됩니다.
이를 해결하기 위해선 read()를 사용하기 전에 항상 현재 소켓이 readable 한지를 확인을 하고 만약 받아 올게 있다면 그때 read()를 실행해야합니다.
<어떠한 역경에도 굴하지 않는 '하양 지훈'>
#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);
답변 감사합니다. :D 소스를 다시 고쳤습니다.계속 프로그램이
답변 감사합니다. :D
소스를 다시 고쳤습니다.
계속 프로그램이 돌면서 클라이언트의 접속이 있는지를 확인하고 접속요청이 확인돼면 접속했다는 메시지를 보여줍니다.
제가 하고 싶은것은 다중 클라이언트 채팅인데요...
그래서 여기 소스에 클라이언트의 값을 받아서 처리하는 부분을 넣고 싶습니다.
어느 부분에 넣어야 할지 감을 못잡겠습니다.
머리가 안좋은건지... 엄청 해메고 있습니다. :cry:
내손안에는 아직 비장의 무기가 남아 있다.
그것은 희망이다.
-나폴레옹-
음... 근데... select() socket의 기본개념은 잡고 프로그
음... 근데... select() socket의 기본개념은 잡고 프로그래밍을 하시는지 좀많이 약간은 의심스럽군요...-_-ㅋ
아주 기본적인 흐름도 정리가 아직 안되신거 같은데...
socket, select() 좀 더 자료를 찾고 읽어 보신다음에 진행을 하시는게 좋을거 같군요.
지금과 같이 하다간 잘 되면 좋은거고 안되면 재수없는 정도 밖에 되질 않을거 같군요.
<어떠한 역경에도 굴하지 않는 '하양 지훈'>
추신_개념없는 프로그래밍은 빛 없는 불과 같은법...
#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);
먼저 답변 감사합니다. ^^이곳처럼 답변잘해주는 게시판은 없다고 봅니
먼저 답변 감사합니다. ^^
이곳처럼 답변잘해주는 게시판은 없다고 봅니다.
그만큼 많은 분들이 글을 읽어 주신다는 말씀이겠죠.
나름대로 사이트 이곳저곳도 찾아서 읽어보고...책도 구입해서 봤습니다.
모두 여러번 읽어 봤지만 솔직히 내용전부를 이해하지는 못합니다. (이해력이 딸리는건지...ㅡ_ㅡa)
어느정도 생각만 가지고 있어서 제 생각에는 직접 해보면서 하는것이 더 좋을듯해서 직접 프로그램을 짜 보려고 한것입니다.
맨땅에 헤딩하는 기분입니다.
음...다시 말씀드리면 프로그램을 다 짜달라는 것은 아니구요.^^a 맥만 짚어 달라는 말이였습니다.
워낙에 무식하게 프로그램에 덤비다 보니...온몸이 고생하네요....
학습방법이 틀린건가요? ㅡㅡa
간단하게 라도 좋으니...맥이라도 짚어 주십시요.
내손안에는 아직 비장의 무기가 남아 있다.
그것은 희망이다.
-나폴레옹-
프로그래밍을 하실 떄...확실한 이해없이 한다는건 정말
프로그래밍을 하실 떄...
확실한 이해없이 한다는건 정말 아주 위험천만한 방법입니다.
말그대로 맨땅에 헤딩을 해서 프로그래밍을 하게 되는데...
이건 별로 남는게 없습니다.
설령 원하는 프로그래밍을 완성을 한다고 하더라도...
이해를 바탕에 두지 않고 한 것은 쉽게 잊어 버리게되고...
응용은 엄두도 못내게 되는거죠...
이건 현재의 이쪽의 현실이긴 하지만...
처음 배울 때...
시간이 좀 걸리더라도...
차근이 수순을 밝아 나가는게... 이쪽에서의 생명을 오래가져가고...
원하는 프로그래밍을 할 수 있습니다.
일다은 select() 이부분 같은 경우는 언제나 강조해도 지나침이 없는...
스티븐스 아저씨의 책을 보세요.
네트웍프로그램 Vol.1 여기에 select() 전반적인 흐름과 함수에 대한 설명도 잘 되어 있습니다.
그리고 당연히 socket 에 대한 설명도 아주 너무 잘 되어 있습니다.
이 내용들을 전체 보시고...
다시 코드를 보시면은 문제점과 해결 방법이 보이실 겁니다.
그럼... 원하시는 프로그램 성공하시길 바랍니다~~~
<어떠한 역경에도 굴하지 않는 '하양 지훈'>
#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);
답변감사합니다.그럼 제가 공부한것이 맞는지 확인좀 부탁드립니다.저
답변감사합니다.
그럼 제가 공부한것이 맞는지 확인좀 부탁드립니다.
저는 TCP/IP를 이용한 소켓 통신을 공부하고 있습니다.
먼저 서버와 클라이언트로 나눠서 정리 해보겠습니다.
서버에서는 처음에 소켓을 생성(sock)하고 생성된 소켓에 주소를 더해주고(bind)해주고 클라이언트의 접속요청을 기다(listen)렸다가 접속 요청이 들어오면 접속요청에 관한 승락(accept)을 해주고 연결된 소켓을 통해서 데이터를 보내고(read, write) 받을수 있는것으로 알고 있습니다.
클라이언트는 소켓을 생성하고(sock) 서버에 접속 시도(connect)를 한후에 접속이 되면 통신하는 것으로 알고 있습니다.
이부분에서 다중으로 클라이언트가 붙는것을 처리하려고 fork라는 것이 나온것으로 알고 있습니다. fork는 부모 프로세스를 그대로 똑같이 복사하는 함수로 알고 있습니다. 소켓 통신의 서버부분에서 클라이언트가 접속해 오면 fork 함수로 프로세스를 하나더 생성해서 클라이언트와 통신을 하게하고 부모 프로세스는 다른 클라이언트의 접속요청을 대기하는것으로 알고 있습니다.
fork라는 함수가 클라이언트의 요청마다 프로세스를 생성하기 문제때문에 나온것이 select와 poll 방식으로 알고 있습니다. 이것들도 문제점이 있어서 지금은 쓰레드라는 것이 나온것으로 알고 있습니다.
글이 길어지네요...정리하면서 쓰다 보니... ㅡ_ㅡ;;
먼저 여기까지 제가 제대로 알고 있는것인가요???
한번에 다 공부는 못할꺼 같아서 select 부분을 공부하고 있습니다.
select는 FD_SET(c, (fd_set *set)&readfd); 매크로로 readfd라는 집합에 c를 등록하고 select문에서 정해진 시간동안 루프를 돌면서 집합에 특정비트가 1이 돼어 있는지를 검사합니다. 만약 변화되었다면 FD_ISSET매크로에서 적당한 작업을 해주는것으로 알고 있습니다. 제가 필요한 곳에 적용해서 보면 FD_ISSET 매크로에 클라이언트의 요청을 처리(accept)하는 부분이 들어가줘야 하는것으로 알고 있습니다.
여기까지는 제대로 알고 있는건가요?
여기까지 맞다면 제 생각에는 FD_ISSET 매크로 부분에서 열린 소켓에 대해서 read나 write를 해주면 통신이 돼는것이 아닌가요?
루프문 안에서
if(FD_ISSET(sock_Num, &readfd)){
acc_sock = accept(sock_Num, &server_addr, sizeof(server_addr));
read(acc_sock,BUF, sizeof(BUF));
write(acc_sock,BUF, sizeof(BUF));
}
대충 이런식으로 처리하면 서버 접속한 클라이언트는 계속 통신을 하면서 서버가 다른 클라이언트의 요청을 받을수 있는거 아닌가요?
기초가 부실해서 그런지... 다른 방식으로 처리를 해줘야 한는건지..
제가 더 생각해줘야 할부분이 어떤것이 있을까요?
긴글 읽어 주셔서 감사합니다.
제가 제대로 공부한것인지 확인 부탁드립니다.
내손안에는 아직 비장의 무기가 남아 있다.
그것은 희망이다.
-나폴레옹-
forking, select(), polling, thread() 이 것
forking, select(), polling, thread() 이 것들은 한 방법일 뿐이고...
어떤게 절대적으로 좋은것은 없습니다.
그때그때 상황에 맞게 선택을 하는게 가장 좋은 방법이 될것입니다.
그리고 select()에서는 IS_FDSET()에서 이 소켓이 read or write or exception 상태인지 확인 가능합니다.
만약 readable 하면 read()로 값을 읽어 들이면 되고,
writable 한 상태이면 write() 하고,
exception 이 일어난 경우는 적당한 예외 처리를 해주면 됩니다.
근데... 지금코드는 readable 만 확인 한 후...
read()로 block된 상태라 다음으로 넘어가지 않는것 같군요.
다시 한 번 Stevens의 Network Programming 을 읽어 보시고...
고민을 해보시길...
<어떠한 역경에도 굴하지 않는 '하양 지훈'>
#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);
답변감사합니다.목표는 다중채팅인데.....하루종일 소스만 보다가.
답변감사합니다.
목표는 다중채팅인데.....
하루종일 소스만 보다가...
이해하기 힘든 부분이 생겼습니다.
루프문 안에서 서버 소켓 번호를 찍어봤습니다.
번호가 0이 넘어오더군요. 이상하다 싶어서...
밑에처럼 바꿨습니다. accept 문을 위로 빼줬습니다.
그랬더니..그제서야 통신이 돼더군요... 소켓 번호들이 제대로 넘어왔습니다.
원래 이런건지...문법상으로는 맞는거 같은데...다른 분들도 그런건가요?
이젠 들어오는 연결들을 구분해주는 부분만 하면 어느정도 서버가 완성될꺼 같습니다.
감사합니다. :)
내손안에는 아직 비장의 무기가 남아 있다.
그것은 희망이다.
-나폴레옹-
당연히 if() 조건문 안에서도 같은 이벤트가 발생해야 합니다.만약
당연히 if() 조건문 안에서도 같은 이벤트가 발생해야 합니다.
만약 안에 넣고 빼고에 차이가 있다면, 분명 어딘가에 오류가 있는 거겠죠.
프로그램에 이상이 있거나, 컴파일러에 이상이 있거나...
가끔씩 컴파일러 오류로 상황은 다르지만 갑자기 소켓넘버가 바뀌는 경험도 한 적이 있긴하죠...
<어떠한 역경에도 굴하지 않는 '하양 지훈'>
#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);
안녕하세요....
저도 잘은 모르나 제가 생각하는 부분을 적자면..
일단 소켓의 생성에는 무리가 없습니다.
select를 사용하시는 이유에 대해서 한 번 고민해 보시구요.
아주 일반적인 경우는.....
1. 소켓생성
2. 소켓 바인드
3. 소켓 리슨
4. accept 상태...(이 시점에서 접속을 기다리게되죠...더 진전되지 않습니다)
5. 접속이되면 accept에서 FD를 리턴해 줍니다.
6. 이 fd를 fd_set으로 하고 select문에서 이제 다시 기다리게 되죠.. 소켓에 데이타가 들어오느냐.. 내가 처리할 데이타가 있나? 하구요.. 물론 select는 timeout 시간까지 기다려주다가 시간이 지나도록 아무 일이 없으면, timout 리턴하는 것이구요. 뭔가 일이 생기면 바로 그 fd를 리턴합니다. 그 부분에 대한 처리는 위에 답변이 되었구요...
이런 flow를 생각하신다면 위에 소스에 수정할 부분이 떠오르실겁니다.
물론 무수한 방법이 있겠지만,, 다중이라면 accept에서 접속이 되면 넘겨받은 fd를 쓰레드나 fork에서 처리해 주면 아주 자연스럽지 않을까 합니다. 그리고 넘겨주고 바로 다시 accept상태로 가야 다른 유저의 접속을 받을 수 있을테니까요.
그럼.. 조금이남아 도움이 되었으면 합니다...
세상은 넓고, 할 일은 많은데, 난 숨만 쉬고 있니?
댓글 달기