귀속말 구현 방법??????

namola의 이미지

제가 만든 채팅서버 및 클라이언트 입니다.귀속말을 구현할려고 하는데...
어케 해야할지 모르겠습니다.
다음은 서버 코드 입니다.

#include         <stdio.h>
#include         <fcntl.h>
#include         <stdlib.h>
#include         <signal.h>
#include         <sys/socket.h>
#include         <sys/file.h>
#include         <netinet/in.h>

#define MAXLINE         1024
#define MAX_SOCK         512

char *escapechar = "exit\n";
int readline(int, char *, int);

int main(int argc, char *argv[])  {
   char         rline[MAXLINE], my_msg[MAXLINE];
   char         *start = "대화방에 오신걸 환영합니다...\n";
   int         i, j, n;
   int         s, client_fd, clilen;
   int        nfds;                        /* 최대 소켓번호 +1 */
   fd_set        read_fds;        /* 읽기를 감지할 소켓번호 구조체 */
   int        num_chat = 0;                /* 채팅 참가자 수 */
   /* 채팅에 참가하는 클라이언트들의 소켓번호 리스트 */
   int         client_s[MAX_SOCK];
   struct sockaddr_in         client_addr, server_addr;
   
   if(argc < 2)  {
      printf("실행방법 :%s 포트번호\n",argv[0]); 
      return -1;
   }
   
   printf("대화방 서버 초기화 중....\n");

   /* 초기소켓 생성 */
   if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)  {
      printf("Server: Can't open stream socket.");   
      return -1;
   }
   
   /* server_addr 구조체의 내용 세팅 */
   bzero((char *)&server_addr, sizeof(server_addr));  
   server_addr.sin_family = AF_INET;              
   server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
   server_addr.sin_port = htons(atoi(argv[1]));     
   
   if (bind(s,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) {
      printf("Server: Can't bind local address.\n");
      return -1;
   }
   
   /* 클라이언트로부터 연결요청을 기다림 */
   listen(s, 5);

   nfds = s + 1;                /* 최대 소켓번호 +1 */
   FD_ZERO(&read_fds);
   
   while(1) {
      /* (최대 소켓번호 +1) 값을 갱신 */
      if((num_chat-1) >= 0)  nfds = client_s[num_chat-1] + 1;

      /* 읽기 변화를 감지할 소켓번호를 fd_set 구조체에 지정 */
      FD_SET(s, &read_fds);
      for(i=0; i<num_chat; i++)  FD_SET(client_s[i], &read_fds);
      
          /*--------------------------------------- select() 호출 ----------------------------------------- */
      if (select(nfds, &read_fds, (fd_set *)0, (fd_set *)0,(struct timeval *)0) < 0) {
             printf("select error\n");
             return -1;
      }
            /*------------------------------ 클라이언트 연결요청 처리 ------------------------------- */
      if(FD_ISSET(s, &read_fds)) {
             clilen = sizeof(client_addr);
             client_fd = accept(s, (struct sockaddr *)&client_addr, &clilen);

             if(client_fd != -1)  {
                    /* 채팅 클라이언트 목록에 추가 */
                    client_s[num_chat] = client_fd; 
                    num_chat++;
                    send(client_fd, start, strlen(start), 0);
                    printf("%d번째 사용자 추가.\n",num_chat);
             }
      }
      
      /*------ 임의의 클라이언트가 보낸 메시지를 모든 클라이언트에게 방송 ----- */
      for(i = 0; i < num_chat; i++)  {
            if(FD_ISSET(client_s[i], &read_fds)) {
               if((n = recv(client_s[i], rline, MAXLINE,0))  > 0)  {
                 rline[n] = '\0';

                 /* 종료문자 입력시 채팅 탈퇴 처리 */
                 if (exitCheck(rline, escapechar, 5) == 1) {
                     shutdown(client_s[i], 2);
                     if(i != num_chat-1)     client_s[i] = client_s[num_chat-1];
                     num_chat--;
                     continue;
                        }

                  /* 모든 채팅 참가자에게 메시지 방송 */        
                  for (j = 0; j < num_chat; j++)  send(client_s[j], rline, n, 0);
                  printf("%s", rline);
               }
            }
      }
   }
}

/* ------------------------------- 종료문자 확인 함수 ---------------------------- 
exitCheck()는 다음의 세 개의 인자를 필요로 한다
        rline: 클라이언트가 전송한 문자열 포인터
        escapechar: 종료문자 포인터
        len: 종료문자의 크기
---------------------------------------------------------------------------------------------*/
int exitCheck(rline, escapechar, len)
  char        *rline;                /* 클라이언트가 전송한 메시지 */
  char        *escapechar;        /* 종료문자 */
  int                len;
  {
     int        i, max;
     char        *tmp;
   
     max = strlen(rline);        
     tmp = rline;
     for(i = 0; i<max; i++) {
        if (*tmp == escapechar[0]) {
                   if(strncmp(tmp, escapechar, len) == 0)
                      return 1;
        } else 
                tmp++;
     } 
   return -1;
}

다음은 클라이언트 입니다.

#include <stdio.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <sys/time.h> 

#define MAXLINE 1024 
#define MAX_SOCK 512 
char *escapechar = "exit\n"; 
int readline(int, char *, int); 

int s; /* 서버와 연결된 소켓번호 */ 
struct Name { 
char n[20]; /* 대화방에서 사용할 이름 */ 
int len;        /* 이름의 크기 */ 
} name; 

int main(int argc, char *argv[]) { 
char line[MAXLINE], sendline[MAXLINE+1]; 
int n, pid, size; 
struct sockaddr_in server_addr; 
int nfds; 
fd_set read_fds;
if( argc < 4 ) { 
printf("실행방법 : %s 호스트 IP주소 포트번호 사용자이름 \n", argv[0]); 
return -1; 
} 

/* 채팅 참가자 이름 구조체 초기화 */ 
sprintf(name.n, "[%s]", argv[3]); 
name.len = strlen(name.n); 

/* 소켓 생성 */ 
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 
printf("Client : Can't open stream socket.\n"); 
return -1; 
} 

/* 채팅 서버의 소켓주소 구조체 server_addr 초기화 */ 
bzero((char *)&server_addr, sizeof(server_addr)); 
server_addr.sin_family = AF_INET; 
server_addr.sin_addr.s_addr = inet_addr(argv[1]); 
server_addr.sin_port = htons(atoi(argv[2])); 
/* 연결요청 */ 
if(connect(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { 
printf("Client : Can't connect to server.\n"); 
return -1; 
} else { 
printf("접속에 성공했습니다..\n"); 
} 
nfds = s + 1; 
FD_ZERO(&read_fds); 
while(1) { 
/* -------------------------------------- selelct() 호출 ---------------------------------------/* 
FD_SET(0, &read_fds); 
FD_SET(s, &read_fds);
if(select(nfds, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) { 
printf("select error\n"); 
return -1; 
} 

/*------------------------- 서버로부터 수신한 메시지 처리 -------------------------*/ 
if (FD_ISSET(s, &read_fds)) { 
char recvline[MAXLINE]; 
int size; 
if ((size = recv(s, recvline, MAXLINE, 0)) > 0) { 
recvline[size] = '\0'; 
printf("%s \n", recvline); 
} 
} 

/* --------------------------------- 키보드 입력 처리 ----------------------------------*/ 
if (FD_ISSET(0, &read_fds)) { 
if (readline(0, sendline, MAXLINE) > 0) { 
size = strlen(sendline); 
sprintf(line, "%s %s", name.n, sendline); 
if (send(s, line, size + name.len, 0) != (size+name.len)) 
printf("Error : Written error on socket.\n"); 
if (size == 5 && strncmp(sendline, escapechar, 5) == 0) { 
printf("Good bye.\n"); 
close(s); 
return -1; 
} 
} 
} /* end of 키보드 입력 처리 */ 
} /* end of while() */ 
}

답변 부탁드리겠습니다.
progcom의 이미지

처리 순서를 잘 생각하시면 될텐데요.

종료 체크하듯이 귓속말 명령어를 체크해서, 해당 클라이언트에게만 메세지를 보내면 됩니다. (물론 자기 자신에게 에코도 해줘야겠지요)

필요한건, 사용자 각각을 인식할 수 있는 정보의 보존입니다.
(사용자는 귓속말명령 - 이름 - 내용 식으로 쓸테니, 각 conn_fd에 해당하는 이름을 기록해둡니다)

무작정 '모르겠다'는 질문보다는, '이렇게 해봤는데 안됩니다. 뭐가 문제인가요?'하는 질문이 더 보기 좋습니다. 스스로 해결하도록 노력하는게 우선이겠지요.

bw001730의 이미지

-_-

simpid의 이미지

이미 채팅 프로그램을 구현했으면서.. 귀속말을 못한다니...
^^;

어디서 소스 갖고 와서 올리고... 말도 안되는 질문 하시는군요.

linuxs의 이미지

namola wrote:

int client_s[MAX_SOCK];

위에 클라이언트 소켓번호를 배열로 가지고 있는데
클라이언트에 대한 모든 정보를 구조체를 만들어 구조체 배열을 사용함으로써 쉽게 가능할것 같은데...
구조체 안에는 소켓번호, 아이디, 아이피어드레스, 등등..을 가지고 있어서
귓속말 할때 아이디를 이용해서 하는데 원하는 아이디를 가지고 있는 소켓번호에게 유니캐스트 하면 될것 같습니다.

꿈은 이루어진다.

bear의 이미지

char n[20]; /* 대화방에서 사용할 이름 */

대화방에서 사용할 이름을 선언 하셨으면 이걸 이용하는것도 괜찮을듯 합니다.

특정 클라이언트로만 전송하기 어려우시다면..

전체 브로드캐스팅 하시고 대화방 사용할 이름을 가지고 선택적으로 뿌려주도록 클라이언트에서 해주셔도 될듯하네요..^^;;;

사용자가 많은 채팅프로그램 이라면 비추입니다.

ageldama의 이미지

잘못된 질문입니다!!!

'귓속말'이거든요;;; 쿨럭;;; 죄송합니다.

----
The future is here. It's just not widely distributed yet.
- William Gibson

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.