#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);
//접속 검사 코드
//로그인 루프
recv(client_socket, buff_rcv,BUFF_SIZE,0);
if(buff_rcv[0]=='n')//새 계정 생성
{
printf("client try to make ID\n");
sprintf(buff_snd,"i\n");
send(client_socket, buff_snd, strlen(buff_snd)+1,0);//id 요구
recv(client_socket, buff_rcv,BUFF_SIZE,0);
sprintf(id[id_num],"%s",buff_rcv);
printf("%dth client's name : %s\n",t_num,buff_rcv);
sprintf(buff_snd,"p\n");
send(client_socket, buff_snd, strlen(buff_snd)+1,0);//password 요구
recv(client_socket, buff_rcv,BUFF_SIZE,0);
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",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 요구
recv(client_socket, buff_rcv,BUFF_SIZE,0);
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
printf("%dth client's name : %s\n",t_num,buff_rcv);
sprintf(buff_snd,"p\n");
send(client_socket, buff_snd, strlen(buff_snd)+1,0);//password 요구
recv(client_socket, buff_rcv,BUFF_SIZE,0);
for(j=0;password[i][j]!='\n';j++)
{
if(password[i][j]!=buff_rcv[j])
break;
}
if(!password[i][j])
continue;
else
printf("%dth client's password : %s\n",t_num,buff_rcv);
sprintf(buff_snd,"a\n");
send(client_socket, buff_snd, strlen(buff_snd)+1,0);//접속 확인
i_num=i;
break;
}
}
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");
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;
}