U E D R , A S I H C RSS

김희성/리눅스멀티채팅

서버

#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[스레드 번호]




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

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

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

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

	while(1)
	{
		rcv=recv(client_socket,buff_rcv,BUFF_SIZE,0);
		if(rcv>0)
		{
			printf("received\n");
			sprintf(buff_snd,"%dth client : %s",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);
		}
		else
		{
			break;
		}
	}

	printf("disconnected\n");
	close(client_socket);
	thread_num[num-1]=0;
    client_socket_array[num-1]=0;
	//스레드가 비활성화 되었으므로 thread_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];
	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);
	recv(client_socket, buff_rcv,BUFF_SIZE,0);
	printf("%s\n",buff_rcv);
	printf("connecting succesed\n");

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

설명

서버를 기반으로한 다중 채팅 코드
Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:28:51
Processing time 0.0160 sec