본문 바로가기

TroubleShooting/Network

FD 최대값 테스트(리눅스 용)

728x90
리눅스에서 FD 사이즈가 기본적으로 1024 인데, include 파일을 수정하여 임의로 확장한 후 테스트를 위해서 다음 소스를 이용하였다. (윈도우용 소스를 급하게 리눅스에서 돌아가도록 작성...)

- 서버

//#include <WinSock2.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <unistd.h>


#define LINE 1024

//#define MAXCLIENT 5

#define MAXCLIENT 1200

#define SERV_PORT 8787


int maxfdp1;

int chatuser; // 채팅 참가자 수

unsigned int client_s[MAXCLIENT];

char *escape = "/quit"; // 종료 명령


/* i번째 유저 계정삭제 */

void disconCli(int i)

{

//closesocket(client_s[i]); // i번째 소켓 닫음

close(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)

{

unsigned int max = user;

int i;

for (i = 0; i < chatuser; i++) {

if (max < client_s[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;

int serversocket, clientsocket, clilen; // 소켓 변수

unsigned short port;

fd_set read_fds;

struct sockaddr_in clientd_addr, server_addr; // 소켓 주소

// WSADATA wsa; // 윈도우즈 소켓선언

int iError;

// 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);

}

port = SERV_PORT;

//ZeroMemory(&server_addr, sizeof(server_addr)); // 초기화

bzero(&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(port);


if (bind(serversocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {

printf("fail bind\n");

exit(0);

}


listen(serversocket, SOMAXCONN); // 연결 대기, SOMAXCONN : 최대 연결수

maxfdp1 = serversocket + 1; // 최대소켓 + 1


printf("#######(%d)\n", FD_SETSIZE);

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, NULL) < 0) {

//iError = WSAGetLastError();

printf("fail select function\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 (strstr(readline, escape)){ // FIXME : 사용자 삭제를 위한 키워드 처리 수정

disconCli(i); // 유저 계정 삭제

continue;

}


readline[n] = '\0';

for (j = 0; j < chatuser; j++) { // 브로드캐스팅

send(client_s[j], readline, n, 0);

}

printf("%s\n", readline);

}

}

}

close(serversocket);

//closesocket(serversocket);

//WSACleanup();

return 0;

}


 
- 클라이언트 : FD 테스트 이므로 서버와는 별개의 장비에서 서버쪽으로 연결하도록 설정하고, loop 문(for, while) 을 이용하여 클라이언트 프로세스를 계속 실행하도록 한다.

//#include <WinSock2.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <unistd.h>


#define TRUE 1

#define FALSE 1


#define  LINE 1024


//DWORD WINAPI ProcessInputSend(LPVOID arg);

int ProcessInputSend(int arg);


char userID[10]; // 유저ID

char line[LINE], chatdata[LINE+1];

struct sockaddr_in server_addr;

//SOCKET serversocket; // 서버 연결 소켓

int serversocket; // 서버 연결 소켓

char *escape = "/quit"; // 종료 명령

//BOOL bIsQuit; // 종료 flag

int bIsQuit; // 종료 flag


void main()

{

//WSADATA wsa; // 소켓

//HANDLE hThread; // 스레드

//DWORD ThreadId;

int size;


bIsQuit = FALSE;

// printf("Input ID : "); // 유저ID 입력

// gets(userID);


// 소켓 초기화

// 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));

bzero(&server_addr, sizeof(server_addr));


server_addr.sin_family = AF_INET; // 소켓 인자들 설정

// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

server_addr.sin_addr.s_addr = inet_addr("192.168.15.15");

server_addr.sin_port = htons(8787);


// 서버와 연결

if (connect(serversocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {

printf("fail connect 2 server\n");

exit(0);

}

else {

printf("connected server\n");

}


/*

// 스레드 생성

hThread = CreateThread(NULL, 0, ProcessInputSend, 0, 0, &ThreadId);

if (hThread == NULL) {

printf("fail make thread\n");

}

else {

CloseHandle(hThread);

}

*/

ProcessInputSend(0);


while (!bIsQuit) {

//ZeroMemory(chatdata, sizeof(chatdata));

bzero(chatdata, sizeof(chatdata));


//if ((size = recv(serversocket, chatdata, LINE, 0)) == INVALID_SOCKET) {

if ((size = recv(serversocket, chatdata, LINE, 0)) == 0) {

printf("recv ERROR\n");

exit(0);

}

else {

chatdata[size] = '\0';

printf("%s\n", chatdata);

}

}


close(serversocket);

// closesocket(serversocket);

// WSACleanup();

}


/* 사용자 입력 */

//DWORD WINAPI ProcessInputSend(LPVOID arg)

int ProcessInputSend(int arg)

{

while(TRUE) {

/*

if (fgets(chatdata, LINE, stdin)) { // 스트림 read

chatdata[strlen(chatdata) - 1] = '\0';

sprintf(line, "\n[%s] : %s", userID, chatdata); // 버퍼의 첫 내용을 출력

if (send(serversocket, line, strlen(line), 0) < 0) {

printf("Write fail\n");

}


if (strstr(line, escape) != 0) { // 종료명령어

printf("Bye\n");

//closesocket(serversocket);

close(serversocket);

bIsQuit = TRUE;

exit(0);

}

}

*/

}

return 0;

}


 
- 결과 : 서버쪽에서 클라이언트가 접속할때마다 카운트가 계속 증가하기 때문에, 1024 개가 넘어서는지 확인할 수 있다.