Toggle menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

김희성/리눅스계정멀티채팅: Difference between revisions

From ZeroWiki
imported>hsebs
No edit summary
(Repair batch-0004 pages from live compare)
 
(One intermediate revision by one other user not shown)
Line 13: Line 13:
   
   
   
   
  int thread_num[25]; //스레드 번호 (해당 스레드 활성화시 번호 값 + 1, 비활성화시 0)
  int thread_num[25]; //스레드 번호 (해당 스레드 활성화시 번호 값 + 1, 비활성화시 0)
  //ex) thread_num[스레드 번호]==스레드 번호+1
  //ex) thread_num[스레드 번호]==스레드 번호+1
   
   
  int client_socket_array[25]; //클라이언트 소캣, 각 스레드 마다 자신의 번호에 해당하는 소캣 사용
  int client_socket_array[25]; //클라이언트 소캣, 각 스레드 마다 자신의 번호에 해당하는 소캣 사용
  //ex) 스레드가 사용 중인 소캣 == client_socket_array[스레드 번호]
  //ex) 스레드가 사용 중인 소캣 == client_socket_array[스레드 번호]
   
   
   
   
  char id[100][256];
  char id[100][256];
  char password[100][256];
  char password[100][256];
  char id_state[100];
  char id_state[100];
  int id_num;
  int id_num;
   
   
   
   
  char chat[100][BUFF_SIZE+5];
  char chat[100][BUFF_SIZE+5];
  char chat_s[100], chat_e;
  char chat_s[100], chat_e;
   
   
  void* rutine(void* data)//data = &thread_num[스레드 번호]
  void* rutine(void* data)//data = &thread_num[스레드 번호]
  {
  {
  int t_num,i_num;//스레드 번호, 아이디 번호
  int t_num,i_num;//스레드 번호, 아이디 번호
  int client_socket;
  int client_socket;
  char buff_rcv[BUFF_SIZE+5],buff_snd[BUFF_SIZE+5];
  char buff_rcv[BUFF_SIZE+5],buff_snd[BUFF_SIZE+5];
  int rcv;
  int rcv;
  int i,j;
  int i,j;
Line 40: Line 40:
  //사용자가 이해하기 쉽도록 스레드 번호에 +1 값을 쓰도록 한다.
  //사용자가 이해하기 쉽도록 스레드 번호에 +1 값을 쓰도록 한다.
   
   
  client_socket=client_socket_array[t_num-1];
  client_socket=client_socket_array[t_num-1];
  //코드의 간결화를 위해 값을 복사한다.
  //코드의 간결화를 위해 값을 복사한다.
   
   
Line 59: Line 59:
  printf("%dth client disconnected\n",t_num);
  printf("%dth client disconnected\n",t_num);
  close(client_socket);
  close(client_socket);
  thread_num[t_num-1]=0;
  thread_num[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  return;
  return;
  }
  }
   
   
  if(buff_rcv[0]=='n' || buff_rcv[0]=='l')
  if(buff_rcv[0]=='n' || buff_rcv[0]=='l')
  {
  {
  sprintf(buff_snd,"a\n");
  sprintf(buff_snd,"a\n");
Line 80: Line 80:
   
   
   
   
  if(buff_rcv[0]=='n')//새 계정 생성
  if(buff_rcv[0]=='n')//새 계정 생성
  {
  {
  printf("client try to make ID\n");
  printf("client try to make ID\n");
Line 94: Line 94:
  printf("%dth client disconnected\n",t_num);
  printf("%dth client disconnected\n",t_num);
  close(client_socket);
  close(client_socket);
  thread_num[t_num-1]=0;
  thread_num[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  return;
  return;
  }
  }
  sprintf(id[id_num],"%s",buff_rcv);
  sprintf(id[id_num],"%s",buff_rcv);
  for(i=0;i<id_num;i++)
  for(i=0;i<id_num;i++)
  {
  {
  for(j=0;id[i][j];j++)
  for(j=0;id[i][j];j++)
  {
  {
  if(id[i][j]!=buff_rcv[j])
  if(id[i][j]!=buff_rcv[j])
  break;
  break;
  }
  }
  if(!id[i][j])
  if(!id[i][j])
  break;
  break;
  }
  }
Line 123: Line 123:
  printf("%dth client disconnected\n",t_num);
  printf("%dth client disconnected\n",t_num);
  close(client_socket);
  close(client_socket);
  thread_num[t_num-1]=0;
  thread_num[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  return;
  return;
  }
  }
  printf("%dth client's password : %s\n",t_num,buff_rcv);
  printf("%dth client's password : %s\n",t_num,buff_rcv);
  sprintf(password[id_num],"%s",buff_rcv);
  sprintf(password[id_num],"%s",buff_rcv);
   
   
  i_num=id_num;
  i_num=id_num;
Line 151: Line 151:
  printf("%dth client disconnected\n",t_num);
  printf("%dth client disconnected\n",t_num);
  close(client_socket);
  close(client_socket);
  thread_num[t_num-1]=0;
  thread_num[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  return;
  return;
Line 159: Line 159:
  for(i=0;i<id_num;i++)
  for(i=0;i<id_num;i++)
  {
  {
  for(j=0;id[i][j];j++)
  for(j=0;id[i][j];j++)
  {
  {
  if(id[i][j]!=buff_rcv[j])
  if(id[i][j]!=buff_rcv[j])
  break;
  break;
  }
  }
  if(!id[i][j])
  if(!id[i][j])
  break;
  break;
  }
  }
Line 170: Line 170:
  continue;
  continue;
  else
  else
  if(id_state[i])
  if(id_state[i])
  continue;
  continue;
   
   
Line 180: Line 180:
  printf("%dth client disconnected\n",t_num);
  printf("%dth client disconnected\n",t_num);
  close(client_socket);
  close(client_socket);
  thread_num[t_num-1]=0;
  thread_num[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  return;
  return;
  }
  }
   
   
  for(j=0;password[i][j]!='\n';j++)
  for(j=0;password[i][j]!='\n';j++)
  {
  {
  if(password[i][j]!=buff_rcv[j])
  if(password[i][j]!=buff_rcv[j])
  break;
  break;
  }
  }
  if(!password[i][j])
  if(!password[i][j])
  printf("%dth client's password : %s\n",t_num,buff_rcv);
  printf("%dth client's password : %s\n",t_num,buff_rcv);
  else
  else
Line 209: Line 209:
   
   
   
   
  sprintf(buff_snd,"%s has joined",id[i_num]);
  sprintf(buff_snd,"%s has joined",id[i_num]);
  for(i=0;i<20;i++)
  for(i=0;i<20;i++)
  {
  {
  if(thread_num[i])
  if(thread_num[i])
  send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
  send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
  }
  }
   
   
   
   
  id_state[i_num]=1;
  id_state[i_num]=1;
  for(;chat_s[i_num]!=chat_e;chat_s[i_num]++)
  for(;chat_s[i_num]!=chat_e;chat_s[i_num]++)
  {
  {
  sprintf(buff_snd,"%s\n",chat[chat_s[i_num]]);
  sprintf(buff_snd,"%s\n",chat[chat_s[i_num]]);
  send(client_socket, buff_snd, strlen(buff_snd)+1,0);
  send(client_socket, buff_snd, strlen(buff_snd)+1,0);
  }
  }
Line 230: Line 230:
  {
  {
  printf("received\n");
  printf("received\n");
  sprintf(buff_snd,"%s : %s",id[i_num],buff_rcv);
  sprintf(buff_snd,"%s : %s",id[i_num],buff_rcv);
   
   
  for(i=0;i<20;i++)
  for(i=0;i<20;i++)
  {
  {
  if(thread_num[i])
  if(thread_num[i])
  send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
  send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
  }
  }
   
   
   
   
  sprintf(chat[chat_e],"%s",buff_snd);
  sprintf(chat[chat_e],"%s",buff_snd);
   
   
  chat_e++;
  chat_e++;
Line 245: Line 245:
   
   
  for(i=0;i<100;i++)
  for(i=0;i<100;i++)
  if(id_state[i] || i>=id_num)
  if(id_state[i] || i>=id_num)
  chat_s[i]=chat_e;
  chat_s[i]=chat_e;
  }
  }
  else
  else
Line 255: Line 255:
   
   
  printf("disconnected\n");
  printf("disconnected\n");
  sprintf(buff_snd,"%s has left",id[i_num]);
  sprintf(buff_snd,"%s has left",id[i_num]);
  for(i=0;i<20;i++)
  for(i=0;i<20;i++)
  {
  {
  if(thread_num[i])
  if(thread_num[i])
  send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
  send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
  }
  }
  printf("disconnected\n");
  printf("disconnected\n");
  close(client_socket);
  close(client_socket);
  thread_num[t_num-1]=0;
  thread_num[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  client_socket_array[t_num-1]=0;
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  //스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
  id_state[i_num]=0;
  id_state[i_num]=0;
  }
  }
   
   
Line 272: Line 272:
  {
  {
  int server_socket;
  int server_socket;
  pthread_t p_thread[25];
  pthread_t p_thread[25];
  struct sockaddr_in server_addr;
  struct sockaddr_in server_addr;
  struct sockaddr_in client_addr;
  struct sockaddr_in client_addr;
Line 300: Line 300:
   
   
  for(i=0;i<20;i++)
  for(i=0;i<20;i++)
  thread_num[i]=0;
  thread_num[i]=0;
   
   
  while(1)
  while(1)
Line 311: Line 311:
  for(i=0;i<20;i++)
  for(i=0;i<20;i++)
  {
  {
  if(!thread_num[i])
  if(!thread_num[i])
  {
  {
  client_addr_size= sizeof(client_addr);
  client_addr_size= sizeof(client_addr);
  client_socket_array[i] = accept(server_socket, (struct sockaddr*)&client_addr,&client_addr_size);
  client_socket_array[i] = accept(server_socket, (struct sockaddr*)&client_addr,&client_addr_size);
   
   
  thread_num[i]=i+1;
  thread_num[i]=i+1;
  memset(&p_thread[i],0,sizeof(p_thread[i]));
  memset(&p_thread[i],0,sizeof(p_thread[i]));
  pthread_create(&p_thread[i],NULL,rutine,(void *)&thread_num[i]);
  pthread_create(&p_thread[i],NULL,rutine,(void *)&thread_num[i]);
  break;
  break;
  }
  }
Line 341: Line 341:
  void gotoxy(int x,int y)
  void gotoxy(int x,int y)
  {
  {
  printf("\033[%d;%df",y,x);
  printf("\033[%d;%df",y,x);
  //터미널 출력 위치 변경 함수, y값이 화면 길이보다 크면 화면 길이로 처리된다.(버그의 원인)
  //터미널 출력 위치 변경 함수, y값이 화면 길이보다 크면 화면 길이로 처리된다.(버그의 원인)
  fflush(stdout);
  fflush(stdout);
Line 352: Line 352:
  {
  {
  int i;
  int i;
  char buff_rcv[BUFF_SIZE+5];
  char buff_rcv[BUFF_SIZE+5];
  int rcv;
  int rcv;
  while(1)
  while(1)
Line 368: Line 368:
  printf("                                                      ");
  printf("                                                      ");
  gotoxy(0,14);
  gotoxy(0,14);
  printf("%s",&buff_rcv[i]);
  printf("%s",&buff_rcv[i]);
  i+=strlen(&buff_rcv[i])+1;
  i+=strlen(&buff_rcv[i])+1;
  }
  }
  }
  }
Line 386: Line 386:
  void* snd_thread(void *data)
  void* snd_thread(void *data)
  {
  {
  char buff_snd[BUFF_SIZE+5];
  char buff_snd[BUFF_SIZE+5];
   
   
  fgets(buff_snd,BUFF_SIZE,stdin);//버퍼 청소
  fgets(buff_snd,BUFF_SIZE,stdin);//버퍼 청소
Line 410: Line 410:
  {
  {
  struct sockaddr_in server_addr;
  struct sockaddr_in server_addr;
  char buff_snd[BUFF_SIZE+5];
  char buff_snd[BUFF_SIZE+5];
  char buff_rcv[BUFF_SIZE+5];
  char buff_rcv[BUFF_SIZE+5];
  int rcv;
  int rcv;
  int i;
  int i;
  pthread_t p_thread[2];
  pthread_t p_thread[2];
   
   
  client_socket=socket(PF_INET, SOCK_STREAM, 0);
  client_socket=socket(PF_INET, SOCK_STREAM, 0);
Line 462: Line 462:
  return 0;
  return 0;
  }
  }
  if(buff_rcv[0]=='a'|| buff_rcv[0]=='c')
  if(buff_rcv[0]=='a'|| buff_rcv[0]=='c')
  break;
  break;
  }
  }
  if(buff_rcv[0]=='a')
  if(buff_rcv[0]=='a')
  break;
  break;
  }
  }
Line 473: Line 473:
  if(recv(client_socket,buff_rcv,BUFF_SIZE,0)>0)
  if(recv(client_socket,buff_rcv,BUFF_SIZE,0)>0)
  {
  {
  switch(buff_rcv[0])
  switch(buff_rcv[0])
  {
  {
  case 'i' :
  case 'i' :
Line 486: Line 486:
  break;
  break;
  }
  }
  if( buff_rcv[0] == 'a' )
  if( buff_rcv[0] == 'a' )
  break;
  break;
  }
  }
Line 497: Line 497:
  }
  }
   
   
  memset(&p_thread[0],0,sizeof(p_thread[0]));
  memset(&p_thread[0],0,sizeof(p_thread[0]));
  pthread_create(&p_thread[0],NULL,rcv_thread,(void *)NULL);
  pthread_create(&p_thread[0],NULL,rcv_thread,(void *)NULL);
   
   
  memset(&p_thread[1],0,sizeof(p_thread[1]));
  memset(&p_thread[1],0,sizeof(p_thread[1]));
  pthread_create(&p_thread[1],NULL,snd_thread,(void *)NULL);
  pthread_create(&p_thread[1],NULL,snd_thread,(void *)NULL);
   
   
  pthread_join(p_thread[0],(void**)&rcv);
  pthread_join(p_thread[0],(void**)&rcv);
  pthread_join(p_thread[1],(void**)&rcv);
  pthread_join(p_thread[1],(void**)&rcv);
   
   
  close(client_socket);
  close(client_socket);
Line 510: Line 510:
  }
  }


== 설명 ==
서버를 기반으로한 로그인 시스템의 다중 채팅. 아이디로 재접속시 퇴장 시점부터 재접속까지의 대화 기록을 보여준다.

Latest revision as of 00:37, 27 March 2026

서버

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<pthread.h>

#define BUFF_SIZE 1024



int thread_num[25];	//스레드 번호 (해당 스레드 활성화시 번호 값 + 1, 비활성화시 0)
			//ex) thread_num[스레드 번호]==스레드 번호+1

int client_socket_array[25];	//클라이언트 소캣, 각 스레드 마다 자신의 번호에 해당하는 소캣 사용
				//ex) 스레드가 사용 중인 소캣 == client_socket_array[스레드 번호]


char id[100][256];
char password[100][256];
char id_state[100];
int id_num;


char chat[100][BUFF_SIZE+5];
char chat_s[100], chat_e;

void* rutine(void* data)//data = &thread_num[스레드 번호]
{
	int t_num,i_num;//스레드 번호, 아이디 번호
	int client_socket;
	char buff_rcv[BUFF_SIZE+5],buff_snd[BUFF_SIZE+5];
	int rcv;
	int i,j;

	t_num=*((int*)data);
	//사용자가 이해하기 쉽도록 스레드 번호에 +1 값을 쓰도록 한다.

	client_socket=client_socket_array[t_num-1];
	//코드의 간결화를 위해 값을 복사한다.

	recv(client_socket, buff_rcv,BUFF_SIZE,0);
	sprintf(buff_snd,"test\n");
	send(client_socket, buff_snd, strlen(buff_snd)+1,0);
	printf("%dth client connected\n",t_num);
	//접속 검사 코드




	//로그인 루프
	while(1)
	{
		if(recv(client_socket, buff_rcv,BUFF_SIZE,0)<=0)
		{
			printf("%dth client disconnected\n",t_num);
			close(client_socket);
			thread_num[t_num-1]=0;
			client_socket_array[t_num-1]=0;
			//스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
			return;
		}

		if(buff_rcv[0]=='n' || buff_rcv[0]=='l')
		{
			sprintf(buff_snd,"a\n");
			send(client_socket, buff_snd, strlen(buff_snd)+1,0);
			break;
		}
		else
		{
			printf("wrong data\n");
			sprintf(buff_snd,"c\n");
			send(client_socket, buff_snd, strlen(buff_snd)+1,0);
		}
	}


	if(buff_rcv[0]=='n')//새 계정 생성
	{
		printf("client try to make ID\n");


		while(1)
		{
			sprintf(buff_snd,"i\n");
			send(client_socket, buff_snd, strlen(buff_snd)+1,0);//id 요구

			if(recv(client_socket, buff_rcv,BUFF_SIZE,0)<=0)
			{
				printf("%dth client disconnected\n",t_num);
				close(client_socket);
				thread_num[t_num-1]=0;
				client_socket_array[t_num-1]=0;
				//스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
				return;
			}
			sprintf(id[id_num],"%s",buff_rcv);
			for(i=0;i<id_num;i++)
			{
				for(j=0;id[i][j];j++)
				{
					if(id[i][j]!=buff_rcv[j])
						break;
				}
				if(!id[i][j])
					break;
			}
			if(i==id_num)
			{
				break;
			}
		}

		sprintf(buff_snd,"p\n");
		send(client_socket, buff_snd, strlen(buff_snd)+1,0);//password 요구

		if(recv(client_socket, buff_rcv,BUFF_SIZE,0)<=0)
		{
			printf("%dth client disconnected\n",t_num);
			close(client_socket);
			thread_num[t_num-1]=0;
			client_socket_array[t_num-1]=0;
			//스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
			return;
		}
		printf("%dth client's password : %s\n",t_num,buff_rcv);
		sprintf(password[id_num],"%s",buff_rcv);

		i_num=id_num;
		id_num++;

		printf("%dth client made new ID\n",t_num);

		sprintf(buff_snd,"a\n");
		send(client_socket, buff_snd, strlen(buff_snd)+1,0);//접속 확인
	}
	else
	{
		printf("client try to login\n");
		while(1)
		{			

			sprintf(buff_snd,"i\n");
			send(client_socket, buff_snd, strlen(buff_snd)+1,0);//id 요구
			if(recv(client_socket, buff_rcv,BUFF_SIZE,0)<=0)
			{
				printf("%dth client disconnected\n",t_num);
				close(client_socket);
				thread_num[t_num-1]=0;
				client_socket_array[t_num-1]=0;
				//스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
				return;
			}

			for(i=0;i<id_num;i++)
			{
				for(j=0;id[i][j];j++)
				{
					if(id[i][j]!=buff_rcv[j])
						break;
				}
				if(!id[i][j])
					break;
			}
			if(i==id_num)
				continue;
			else
				if(id_state[i])
					continue;


			sprintf(buff_snd,"p\n");
			send(client_socket, buff_snd, strlen(buff_snd)+1,0);//password 요구
			if(recv(client_socket, buff_rcv,BUFF_SIZE,0)<=0)
			{
				printf("%dth client disconnected\n",t_num);
				close(client_socket);
				thread_num[t_num-1]=0;
				client_socket_array[t_num-1]=0;
				//스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
				return;
			}

			for(j=0;password[i][j]!='\n';j++)
			{
				if(password[i][j]!=buff_rcv[j])
					break;
			}
			if(!password[i][j])
				printf("%dth client's password : %s\n",t_num,buff_rcv);
			else
				continue;

			printf("%dth client logined\n",t_num);

			sprintf(buff_snd,"a\n");
			send(client_socket, buff_snd, strlen(buff_snd)+1,0);//접속 확인

			i_num=i;
			break;
		}
	}




	sprintf(buff_snd,"%s has joined",id[i_num]);
	for(i=0;i<20;i++)
	{
		if(thread_num[i])
			send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
	}


	id_state[i_num]=1;
	for(;chat_s[i_num]!=chat_e;chat_s[i_num]++)
	{
		sprintf(buff_snd,"%s\n",chat[chat_s[i_num]]);
		send(client_socket, buff_snd, strlen(buff_snd)+1,0);
	}

	while(1)
	{
		rcv=recv(client_socket,buff_rcv,BUFF_SIZE,0);
		if(rcv>0)
		{
			printf("received\n");
			sprintf(buff_snd,"%s : %s",id[i_num],buff_rcv);

			for(i=0;i<20;i++)
			{
				if(thread_num[i])
					send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
			}


			sprintf(chat[chat_e],"%s",buff_snd);

			chat_e++;
			chat_e%=100;

			for(i=0;i<100;i++)
				if(id_state[i] || i>=id_num)
					chat_s[i]=chat_e;
		}
		else
		{
			break;
		}
	}

	printf("disconnected\n");
	sprintf(buff_snd,"%s has left",id[i_num]);
	for(i=0;i<20;i++)
	{
		if(thread_num[i])
			send(client_socket_array[i],buff_snd,strlen(buff_snd)+1,0);
	}
	printf("disconnected\n");
	close(client_socket);
	thread_num[t_num-1]=0;
	client_socket_array[t_num-1]=0;
	//스레드가 비활성화 되었으므로 thread_num을 0으로 초기화한다.
	id_state[i_num]=0;
}

int main()
{
	int server_socket;
	pthread_t p_thread[25];
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	int client_addr_size;
	int i;

	server_socket=socket(PF_INET, SOCK_STREAM, 0);
	if(server_socket==-1)
	{
		printf("socket error\n");
		exit(1);
	}


	memset(&server_addr,0,sizeof(server_addr));
	server_addr.sin_family	=AF_INET;
	server_addr.sin_port	=htons(4000);
	server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	if(-1==bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
	{
		printf("bind error\n");
		exit(1);
	}


	printf("server started\n");

	for(i=0;i<20;i++)
		thread_num[i]=0;

	while(1)
	{
		if(-1==listen(server_socket,5))
		{
			printf("listen error\n");
			exit(1);
		}
		for(i=0;i<20;i++)
		{
			if(!thread_num[i])
			{
				client_addr_size= sizeof(client_addr);
				client_socket_array[i] = accept(server_socket, (struct sockaddr*)&client_addr,&client_addr_size);

				thread_num[i]=i+1;
				memset(&p_thread[i],0,sizeof(p_thread[i]));
				pthread_create(&p_thread[i],NULL,rutine,(void *)&thread_num[i]);
				break;
			}
		}
		if(i==20)
			printf("error : Too many clients connected");
	}
	close(server_socket);
	return 0;
}

클라이언트

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>

#define BUFF_SIZE 1024
void gotoxy(int x,int y)
{
	printf("\033[%d;%df",y,x);
	//터미널 출력 위치 변경 함수, y값이 화면 길이보다 크면 화면 길이로 처리된다.(버그의 원인)
	fflush(stdout);
}

int client_socket;
int check;

void* rcv_thread(void *data)
{
	int i;
	char buff_rcv[BUFF_SIZE+5];
	int rcv;
	while(1)
	{
		rcv=recv(client_socket, buff_rcv, BUFF_SIZE, 0);
		if(rcv>0)
		{
			while(check==1);
			check=2;
			for(i=0;i<rcv;)
			{
				gotoxy(0,100);//gotoxy의 특징을 이용하여 화면을 한칸 올린다.
				printf("\n");
				gotoxy(0,14);
				printf("                                                       ");
				gotoxy(0,14);
				printf("%s",&buff_rcv[i]);
				i+=strlen(&buff_rcv[i])+1;
			}
		}
		else
		{
			printf("disconnected\n");
			break;
		}
		gotoxy(0,15);
		printf("write message to send :                                          ");
		gotoxy(25,15);
		check=0;
	}
}

void* snd_thread(void *data)
{
	char buff_snd[BUFF_SIZE+5];

	fgets(buff_snd,BUFF_SIZE,stdin);//버퍼 청소
	while(1)
	{
		while(check==2);
		check=1;
		gotoxy(0,15);
		printf("write message to send :                                          ");
		gotoxy(25,15);
		check=0;
		fgets(buff_snd,BUFF_SIZE,stdin);
		check=0;
		if(send(client_socket, buff_snd, strlen(buff_snd)+1,0)<=0)
		{
			printf("disconnected\n");
			break;
		}
	}
}

int main()
{
	struct sockaddr_in server_addr;
	char buff_snd[BUFF_SIZE+5];
	char buff_rcv[BUFF_SIZE+5];
	int rcv;
	int i;
	pthread_t p_thread[2];

	client_socket=socket(PF_INET, SOCK_STREAM, 0);

	if(client_socket==-1)
	{
		printf("socket error\n");
		return 1;
	}
	memset( &server_addr, 0, sizeof( server_addr));
	server_addr.sin_family     = AF_INET;
	server_addr.sin_port       = htons( 4000);
	server_addr.sin_addr.s_addr= inet_addr( "127.0.0.1");

	if(-1==connect(client_socket,(struct sockaddr*)&server_addr, sizeof( server_addr) ) )
	{
		printf("connect error\n");
		return 1;
	}

	//연결 확인
	sprintf(buff_snd,"test\n");
	send(client_socket, buff_snd, strlen(buff_snd)+1,0);
	if(recv(client_socket, buff_rcv,BUFF_SIZE,0)>0)
	{
		printf("connecting succesed\n");
	}
	else
	{
		printf("disconnected\n");
		close(client_socket);
		return 0;
	}

	//로그인 시스템
	while(1)
	{
		printf("new id=n / login=l : ");
		scanf("%s",buff_snd);
		send(client_socket,buff_snd,strlen(buff_snd)+1,0);
		while(1)
		{
			if(recv(client_socket,buff_rcv,BUFF_SIZE,0)<=0)
			{
				printf("disconnected\n");
				close(client_socket);
				return 0;
			}
			if(buff_rcv[0]=='a'|| buff_rcv[0]=='c')
				break;
		}
		if(buff_rcv[0]=='a')
			break;
	}

	while(1)
	{
		if(recv(client_socket,buff_rcv,BUFF_SIZE,0)>0)
		{
			switch(buff_rcv[0])
			{
				case 'i' :
					printf("ID : ");
					scanf("%s",buff_snd);
					send(client_socket,buff_snd,strlen(buff_snd)+1,0);
					break;
				case 'p' :
					printf("PASSWORD : ");
					scanf("%s",buff_snd);					
					send(client_socket,buff_snd,strlen(buff_snd)+1,0);
					break;
			}
			if( buff_rcv[0] == 'a' )
				break;
		}
		else
		{
			printf("disconnected\n");
			close(client_socket);
			return 0;
		}
	}

	memset(&p_thread[0],0,sizeof(p_thread[0]));
	pthread_create(&p_thread[0],NULL,rcv_thread,(void *)NULL);

	memset(&p_thread[1],0,sizeof(p_thread[1]));
	pthread_create(&p_thread[1],NULL,snd_thread,(void *)NULL);

	pthread_join(p_thread[0],(void**)&rcv);
	pthread_join(p_thread[1],(void**)&rcv);

	close(client_socket);
	return 0;
}

설명

서버를 기반으로한 로그인 시스템의 다중 채팅. 아이디로 재접속시 퇴장 시점부터 재접속까지의 대화 기록을 보여준다.