본문 바로가기

과제모음

Thread를 이용한 다중채팅(Server)

반응형
#include <WinSock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define LINE 1024
#define MAXCLIENT 5

int maxfdp1;
int chatuser; // 채팅 참가자 수
int client_s[MAXCLIENT];
char *escape = "exit"; // 종료 명령


void disconCli(int i){ // i번째 유저 계정삭제
closesocket(client_s[i]); // i번째 소켓 닫음
if(i != chatuser-1){
client_s[i] = client_s[chatuser-1];
chatuser--; // 총유저수 줄임
printf("Now On the net %d users\n", chatuser);
}
}

int maxuser(int user){ // 현재 채팅 참가자수를 검색
int max = user;
int i;
for(i = 0; i < chatuser; i++){
max = client_s[i];
}

return max;
}

int main(){
char readline[LINE]; // read buffer
char *start = "Now you connected Server\n"; // 접속알림
int i,j,n, addrlen; // 반복문 & 주소길이리턴
SOCKET serversocket, clientsocket, clilen; // 소켓 변수 선언
fd_set read_fds; // select read 디스크립터
struct sockaddr_in clientd_addr, server_addr; // 소켓 주소
WSADATA wsa; // 윈도우즈 소켓선언
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0){ // 소켓 초기화
exit(1);
}

if((serversocket = socket(AF_INET, SOCK_STREAM, 0)) < 0){ // 소켓 생성
printf("fail make socket\n");
exit(0);
}

ZeroMemory(&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(2600);

if(bind(serversocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){
printf("fail bind\n");
exit(0);
}

listen(serversocket, SOMAXCONN); // 연결 대기
maxfdp1 = serversocket + 1; // 최대소켓 + 1

while(1){
FD_ZERO(&read_fds); // 파일 디스크립터 초기화
FD_SET(serversocket, &read_fds);
for(i=0; i<chatuser; i++){
FD_SET(client_s[i], &read_fds);
}
maxfdp1 = maxuser(serversocket)+1;

if(select(maxfdp1,&read_fds,(fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0){
// select 함수
printf("fail select finction\n");
exit(0);
}

if(FD_ISSET(serversocket, &read_fds)){
// 파일디스크립터에 읽을 데이터가 있으면
addrlen = sizeof(clientd_addr); // 주소길이 지정
// 소켓 연결
clilen = sizeof(clientd_addr);
clientsocket = accept(serversocket, (struct sockaddr *)&clientd_addr, &addrlen);

if(clientsocket == -1){
printf("fail accept\n");
exit(0);
}
client_s[chatuser] = clientsocket;
chatuser++; // 유저증가

send(clientsocket, start, strlen(start), 0);
printf("%d user connected\n", chatuser); // 유저접속알림
}
// 브로드 캐스팅
for(i=0; i<chatuser; i++){ // 접속해 있는 유저수만큼
memset(readline, '\0', LINE);
if(FD_ISSET(client_s[i], &read_fds)){ // 파일 디스크립터 버퍼 확인
if((n=recv(client_s[i], readline, LINE, 0)) <= 0){
disconCli(i);
continue;
}

if(strcmp(escape, "exit") == 0){
disconCli(i); // 유저 계정 삭제
continue;
}

readline[n] = '\0';
for(j=0; j < chatuser; j++){ // 브로드캐스팅
send(client_s[j], readline, n, 0);
}
printf("%s\n", readline);
}
}
}
closesocket(serversocket);
WSACleanup();
return 0;
}
반응형