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)
 
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 512: Line 512:
== 설명 ==
== 설명 ==
서버를 기반으로한 로그인 시스템의 다중 채팅. 아이디로 재접속시 퇴장 시점부터 재접속까지의 대화 기록을 보여준다.
서버를 기반으로한 로그인 시스템의 다중 채팅. 아이디로 재접속시 퇴장 시점부터 재접속까지의 대화 기록을 보여준다.

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;
}

설명

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