[Socket] 서버와 클라이언트 그리고 스레드처리 문제점 질문이요
인1형녀
서버2개와 클라이언트 그리고 스레드 관련문제라 좀 오래걸릴꺼같네요 시간 있으신분만봐주세요 ㅠ,ㅠ질문 제목 : [Socket] 서버와 클라이언트 그리고 스레드처리 문제점 질문이요
질문 요약 :서버2개와 클라이언트, 그리고 스레드처리 진행중 문제점
소스 코드:
------------------------------------------------------------------------------
client.c // 클라이언트
#includestdio.h
#includestdlib.h
#includestring.h
#includesys/types.h
#includesys/socket.h
#includenetinet/in.h
#includeunistd.h
#includepthread.h
#define MAXLINE 127
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr,servaddr2; // 서버소켓주소정보 구조체선언
char buf[MAXLINE+1]; // 메모리 버퍼 선언
int sock,sock2; // 소켓통로
int myid,n;
if(argc != 4) // 실행법 체크
{
printf(use : %s IP SERVER1 PORT SERVER2 PORT\n, argv[0]);
exit(0);
}
if((sock = socket(AF_INET, SOCK_STREAM, 0)) 0) // 인터넷표준 TCP로 소켓공간 형성
{
perror(scoket error);
exit(1);
}
if((sock2 = socket(AF_INET, SOCK_STREAM, 0)) 0) // 인터넷표준 TCP로 소켓공간 형성
{
perror(scoket error);
exit(1);
}
memset(&servaddr, 0, sizeof(servaddr)); // 서버주소구조체 초기화
memset(&servaddr2, 0, sizeof(servaddr2)); // 서버주소구조체 초기화
servaddr.sin_family = AF_INET; // 인터넷 표준 형태
servaddr.sin_port = htons(atoi(argv[2])); // 매개인자 2번쨰 칸을 포트로지정
servaddr2.sin_family = AF_INET; // 인터넷 표준 형태
servaddr2.sin_port = htons(atoi(argv[3])); // 매개인자 3번쨰 칸을 포트로지정
if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) = 0) // 인터넷 표준형식의주소로 구조체주소에 삽입
{
perror(inet_pton error);
exit(0);
}
if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) 0) // 만든소켓에 연결시도
{
perror(서버1에 접속실패 );
exit(0);
}
if(inet_pton(AF_INET, argv[1], &servaddr2.sin_addr) = 0) // 인터넷 표준형식의주소로 구조체주소에 삽입
{
perror(inet_pton error);
exit(0);
}
if(connect(sock2, (struct sockaddr*)&servaddr2, sizeof(servaddr2)) 0) // 만든소켓에 연결시도
{
perror(서버2에 접속실패 );
exit(0);
}
while(1)
{
printf(접속할 숫자 ID를 입력 : );
scanf(%d, &myid); //키보드입력
if( (n = write(sock, &myid, sizeof(myid))) = 0) // 서버로 전달
{
perror(write erorr);
exit(0);
}
printf(receive 서버의 메시지를 기다리는중...\n);
if((n = read(sock2, buf, MAXLINE)) = 0) // 서버로부터 받음
{
perror(read error);
exit(0);
}
buf[n] = 0; // 문자열 끝을 표시
printf(서버2로부터 받은 메시지- %s, buf);
close(sock);
close(sock2);
}
}
------------------------------------------------------------------------------
server1.c // SEND SERVER#includestdio.h
#includestdlib.h
#includestring.h
#includesys/types.h
#includesys/socket.h
#includenetinet/in.h
#includepthread.h
#includeunistd.h
#define MAXLINE 1024
pthread_t tid[10];
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;ALIZER;
struct sockaddr_in servaddr, cliaddr, servaddr2; // 서버와 클라 구조체 주소 선언
int listen_sock, accp_sock[10], server2sock, nbyte, addrlen = sizeof(cliaddr); //받는소켓, 수락소켓, 주소길이 선언
char buf[MAXLINE+1]; // 메모리 버퍼 선언
char buf2[MAXLINE+1];
int cnt=0,myid;
void *thread_work(void *arg)
{
int *n;
n = (int *)arg;
printf(스레드[%d] START\n, *n);
read(accp_sock[*n], &myid, sizeof(int)); // 클라로부터 메시지 받는다 printf(클라이언트로부터 [C%d]를 받았습니다., myid);
if(accp_sock 0) // 접속 수락 실패시 오류
{
perror(accept fail);
exit(0);
}
pthread_mutex_lock(&lock); // 뮤텍스 LOCK을 검니다
write(server2sock, &myid, sizeof(myid)); // server2
pthread_mutex_unlock(&lock); // 뮤텍스 UNLOCK을 검니다
printf( [C%d]를 서버2로 전송을 하였습니다., myid);
close(accp_sock[*n]);
}
int main(int argc, char *argv[])
{
if(argc != 3) // 실행방법 체크
{
printf(use : %s [server1port] [server2port] \n, argv[0]);
exit(0);
}
if((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) 0) // 받는 소켓을 정의 지정
{
perror(socket error);
exit(0);
}
if((server2sock = socket(AF_INET, SOCK_STREAM, 0)) 0) // 인터넷표준 TCP로 소켓공간 형성
{
perror(scoket error);
exit(1);
}
memset(&servaddr, 0, sizeof(servaddr)); // 서버주소 초기화
memset(&cliaddr, 0, sizeof(cliaddr)); // 클라주소 초기화
memset(&servaddr2, 0, sizeof(cliaddr)); // 클라주소 초기화
servaddr.sin_family = AF_INET; // 서버1
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(atoi(argv[1]));
servaddr2.sin_family = AF_INET; // 서버2
servaddr2.sin_port = htons(atoi(argv[2]));
if(bind(listen_sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) 0) // listen_sock과 서버구조체 결합
{
perror(bind error);
exit(0);
}
if(inet_pton(AF_INET, 127.0.0.1, &servaddr2.sin_addr) = 0) // 서버2 로
{
perror(inet_pton error);
exit(0);
}
if(connect(server2sock, (struct sockaddr*)&servaddr2, sizeof(servaddr2)) 0) // 서버 2로
{
perror(connect error);
exit(0);
}
listen(listen_sock, 10); // 접속준비 완료
while(1)
{
accp_sock[cnt] = accept(listen_sock, (struct sockaddr*)&cliaddr, &addrlen);
printf(CNT : %d 클라이언트 소켓 : %d 클라이언트포트:%d 가 접속했습니다.\n, cnt, listen_sock, servaddr.sin_port);
if((pthread_create(&tid[cnt], NULL, thread_work, &cnt)) 0) // 스레드 생성
perror(쓰레드 생성에 실패하였습니다.);
cnt++;
}
int i;
void *tret;
for(i=0;i=cnt;i++)
pthread_join(tid[cnt], &tret);
close(listen_sock);
}
------------------------------------------------------------------------------
client.c // 클라이언트
#includestdio.h
#includestdlib.h
#includestring.h
#includesys/types.h
#includesys/socket.h
#includenetinet/in.h
#includeunistd.h
#includepthread.h
#define MAXLINE 127
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr,servaddr2; // 서버소켓주소정보 구조체선언
char buf[MAXLINE+1]; // 메모리 버퍼 선언
int sock,sock2; // 소켓통로
int myid,n;
if(argc != 4) // 실행법 체크
{
printf(use : %s IP SERVER1 PORT SERVER2 PORT\n, argv[0]);
exit(0);
}
if((sock = socket(AF_INET, SOCK_STREAM, 0)) 0) // 인터넷표준 TCP로 소켓공간 형성
{
perror(scoket error);
exit(1);
}
if((sock2 = socket(AF_INET, SOCK_STREAM, 0)) 0) // 인터넷표준 TCP로 소켓공간 형성
{
perror(scoket error);
exit(1);
}
memset(&servaddr, 0, sizeof(servaddr)); // 서버주소구조체 초기화
memset(&servaddr2, 0, sizeof(servaddr2)); // 서버주소구조체 초기화
servaddr.sin_family = AF_INET; // 인터넷 표준 형태
servaddr.sin_port = htons(atoi(argv[2])); // 매개인자 2번쨰 칸을 포트로지정
servaddr2.sin_family = AF_INET; // 인터넷 표준 형태
servaddr2.sin_port = htons(atoi(argv[3])); // 매개인자 3번쨰 칸을 포트로지정
if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) = 0) // 인터넷 표준형식의주소로 구조체주소에 삽입
{
perror(inet_pton error);
exit(0);
}
if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) 0) // 만든소켓에 연결시도
{
perror(서버1에 접속실패 );
exit(0);
}
if(inet_pton(AF_INET, argv[1], &servaddr2.sin_addr) = 0) // 인터넷 표준형식의주소로 구조체주소에 삽입
{
perror(inet_pton error);
exit(0);
}
if(connect(sock2, (struct sockaddr*)&servaddr2, sizeof(servaddr2)) 0) // 만든소켓에 연결시도
{
perror(서버2에 접속실패 );
exit(0);
}
while(1)
{
printf(접속할 숫자 ID를 입력 : );
scanf(%d, &myid); //키보드입력
if( (n = write(sock, &myid, sizeof(myid))) = 0) // 서버로 전달
{
perror(write erorr);
exit(0);
}
printf(receive 서버의 메시지를 기다리는중...\n);
if((n = read(sock2, buf, MAXLINE)) = 0) // 서버로부터 받음
{
perror(read error);
exit(0);
}
buf[n] = 0; // 문자열 끝을 표시
printf(서버2로부터 받은 메시지- %s, buf);
close(sock);
close(sock2);
}
}
------------------------------------------------------------------------------
server2.c //RECEIVE SERVER
#includestdio.h
#includestdlib.h
#includestring.h
#includesys/types.h
#includesys/socket.h
#includenetinet/in.h
#includepthread.h
#includeunistd.h
#define MAXLINE 1024
void *thread_manage(void *arg);
void *thread_server1(void *arg);
pthread_t tid1,tid2;
struct sockaddr_in servaddr, cliaddr; // 서버와 클라 구조체 주소 선언
int listen_sock, serv1_sock, client_sock, nbyte, addrlen = sizeof(cliaddr); //받는소켓, 수락소켓, 주소길이 선언
char buf[MAXLINE]; // 메모리 버퍼 선언
int cnt=1nt cnt=1,myid; //클라의 접속정보
void *thread_server1(void *arg) // 서버1로부터 받는자료 저장하는 스레드
{
printf(th_server1 스레드가 START\n);
read(serv1_sock, &myid, sizeof(myid)); // 서버1한테 메시지 받는다
printf(서버1로부터 [C%d]를 받았습니다.\n, myid);
sprintf(buf, [C%d] - [S1] - [S2], myid);
write(serv1_sock, buf, strlen(buf)); // 클라에게 메시지 전송
close(serv1_sock);
}
void *thread_manage(void *arg) //클라이언트 데이터베이스 정보관리 스레드
{
printf(th_manage 스레드가 START\n);
while(1)
{
client_sock = accept(listen_sock, (struct sockaddr*)&cliaddr, &addrlen);
printf(클라이언트 소켓 : %d 클라이언트포트:%d 가 접속했습니다.\n, listen_sock, cliaddr.sin_port);
if(client_sock 0) // 접속 수락 실패시 오류
{
perror(accept fail);
exit(0);
}
read(client_sock, &myid, sizeof(myid)); // 클라로부터 메시지 받는다
printf(%d번 클라이언트가 접속했습니다.\n, myid);
close(client_sock);
}
printf(th_manage 스레드가 END.\n);
}
int main(int argc, char *argv[])
{
void *tret;
if(argc != 2) // 실행방법 체크
{
printf(use : %s port\n, argv[0]);
exit(0);
}
if((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) 0) // 받는 소켓을 정의 지정
{
perror(socket error);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr)); // 서버주소 초기화
memset(&cliaddr, 0, sizeof(cliaddr)); // 클라주소 초기화
servaddr.sin_family = AF_INET; // 인넷 표준
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 현 컴의 주소정보를 IP로지정
servaddr.sin_port = htons(atoi(argv[1])); // 포트는 매개인자로 받아 적음
if(bind(listen_sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) 0) // listen_sock과 서버구조체 결
{
perror(bind error);
exit(0);
}
if( (listen(listen_sock, 10) == -1) )
perror(Listen Error );
printf(서버1의 접속을 기다립니다.\n);
serv1_sock = accept(listen_sock, (struct sockaddr*)&cliaddr, &addrlen);
printf(SEVER1 소켓 : %d\nSERVER1 포트:%d\n, listen_sock, cliaddr.sin_port);
printf(서버1과 연결이 완료되었습니다.\n);
if((pthread_create(&tid1, NULL, thread_server1, NULL)) 0) // 서버 스레드 생성
perror(서버1 쓰레드 생성에 실패하였습니다.);
if((pthread_create(&tid2, NULL, thread_manage, NULL)) 0) // 클라 스레드 생성
perror(클라 쓰레드 생성에 실패하였습니다.);
pthread_join(tid1, &tret);
pthread_join(tid2, &tret);
close(listen_sock);
}
질문 내용 :
솔직히 말씀드려서 과제 맞습니다. 하지만 절대 해달라고 구걸하지는 않겠습니다.
밤새 해도 도저히 답이 않나와서... 제가 설꼐를 잘못하구있는건지 그래서 확인만 요청 해보려고하거든요
제가 해매는부분은 :
SEND서버1 와 RECEIVE서버2 와 각 클라이언트가 존재하구요
클라이언트는 저 두가지 서버에 모두 동시 접속을합니다.
클라가 SEND서버에 숫자를보내면 SEND서버를 통해 RECEIVE서버가 그것을받아서
클라가 다시 RECEIVE서버에게 도로 돌려받습니다.
이거 하는중 제가 막히는게 있는데
SEND서버는 처음에 ACCEPT 블럭상태가 됩니다.
그리고 클라가 접속에 성공하면, 스레드를 생성하여 그 생성된 스레드안에선 READ블럭을 타게됩니다.
왜냐면 클라로부터 문자를 입력받아야하기때문이죠. 하지만 여기서 문제점!!
저거때문에 제가 지금 완전히 막혔는데요......
처음 실행되는부분 ACCEPT하는 부분이 무한루프 돌려야되고......
접속에 성공한 클라 스레드두 READ때문에 무한루프를 타야되요
그런데 블럭은 1개밖에 않되잖아요? 방법없나요 ㅠㅠ 제발 부탁드립니다
혹시나 뮤텍스 동기화 해봤는데 그것으로도 않되더군요.. 역시나 타이밍이 같아서 그런지이것은 요구사항인데 제가 위에 설명이 부족할꺼같아서 혹시몰라적어요
제가 막혀서 진행못하는부분만 해결하면 혼자서 해결할수있을꺼같아요. 개념이 부족한거같구...-서버 2개와 3개의 클라이언트를 구성한다
-각 클라이언트는 자기 아이디번호를 가지고 기동하며, 서버 2와 소켓을 연결할 때는 자기 클라이언트 번호를 이용해 통신하며, 서버 2는 소켓 번호와 클라이언트 번호에 대한 정보를 관리해야 한다.
-각 클라이언트는 무한루프를 돌며, 사용자 입력이 있을 때마다, 서버1 에 C#라는 메시지를 보낸다. C#에서 #은 클라이언트 번호를 의미한다.
-서버 1은 각 클라이언트에 대한 소켓을 생성해야 하며, 스레드를 이용해 클라이언트를 서비스해야 한다.
-서버 1의 각 스레드는 클라이언트에서 받은 문자열은 서버2로 “S#-C#” 이라는 형식을 이용해, 송신을 하며, 이 때 서버1과 서버2 사이에는 소켓이 하나 밖에 없으므로, 뮤텍스를 사용하여야 한다.
-서버 2에는 서버1으로부터의 메시지를 받아, 큐에 저장하는 스레드가 있어야 하며, 메시지 큐는 뮤텍스를 사용해 동기화 하여야 한다.
-서버 2의 또 다른 스레드는 메시지 큐에 내용이 있으면 해당 클라이언트에 “C#-S1-S2”라는 형식의 문자열을 발송한다.
-클라이언트는 서버 2로부터 문자열을 받으면, 받은 일시와 시간을 적고 받은 메시지를 출력한다.
번호 | 제 목 | 글쓴이 | 날짜 |
---|---|---|---|
2692401 | 유닉스안에서 C언어를 이용한 명함 만들기 입니다; 이해안가는 부분이있네요 | 2gether | 2025-04-22 |
2692374 | 고수님들 댓글 마니부탁해요!!! (2) | 엄지 | 2025-04-22 |
2692343 | scnaf에 자꾸 선언을 참조하라는데;; (8) | 도래 | 2025-04-22 |
2692282 | 도스상에서 생성된 exe파일에 press~ 뜨게 하기 (4) | 회사원 | 2025-04-21 |
2692256 | scanf("%*c"); ㅠㅠ 고수님들 | 거북이 | 2025-04-21 |
2692230 | 하노이탑 질문입니다. (1) | 미쁘다 | 2025-04-21 |
2692210 | 정보 올림피아드 문제인데.. 풀이 과정이 궁금합니다.(재귀함수) (5) | 물티슈 | 2025-04-20 |
2692144 | C언어와 리눅스에 대한 질문입니다. | 싴흐한세여니 | 2025-04-20 |
2692114 | 컨텍스트 스위칭하는데 걸리는 시간 측정.. | YourWay | 2025-04-19 |
2692086 | 간접참조 연산자, 증감연산자 질문이용! (2) | 블랙캣 | 2025-04-19 |
2692056 | 주석좀 달아주세요. 몇개적엇는데 몇개만달아주세요. (2) | DevilsTears | 2025-04-19 |
2691978 | 진수 쉽게 이해하는법... (3) | 지지않는 | 2025-04-18 |
2691949 | getchar() 한 문자를 입력받는 함수 질문 | 채꽃 | 2025-04-18 |
2691919 | 배열 정렬 및 합치기 질문입니다. | 사과 | 2025-04-18 |
2691845 | c언어왕초보 질문이 있습니다........ | 루나 | 2025-04-17 |
2691815 | void add(int num); 함수... (4) | 살랑살랑 | 2025-04-17 |
2691756 | 명령 프롬프트 스크롤바가 없어요 | 두메꽃 | 2025-04-16 |
2691725 | 자료구조에 관련해서 질문이 있어 글을 올립니다. | 누리알찬 | 2025-04-16 |
2691697 | if 문에서 구조체 배열에 저장되있던 문자열 검사하는 법 ? (2) | 민트맛사탕 | 2025-04-16 |
2691678 | C언어 함수 질문이요~!!! | 연보라 | 2025-04-15 |