socket 배열

익명 사용자의 이미지

안녕하세요

클라이언트 관리 배열, epoll에서 클라이언트 관리 배열을 만들었는 데 여기서 어떻게 수정하면 될까요?

#include "libDefine.h"
 
void signalHandlerServer(int nSignal);
 
int setNonblockSocket(int nFileDescriptor);
 
int g_nServerSocket = -1;					/* server socket file descriptor */
int g_nClientSocket = -1;					/* client 관리 배열 */
int g_nClient[MAXCLIENT] = {0, };
int g_nClientCount = 0;
 
//int g_nClientSocket[MAXCLIENT] = {0, };
//int nClientCount = 0;
//int g_nClientSocket = -1;							/* client socket file descriptor */
 
int main(int argc, char *argv[])
{
	int nPort = -1;
	char szMsg[SIZEBUFFER + 1] = {0,};			/* 수신용 버퍼 */
	int nReadLength = 0;								/* 받은 메시지 길이 저장 변수 */
	struct sockaddr_in stClientAddr = {0,};	/* 클라이언트 주소 저장할 구조체 */
	unsigned int uClientAddrSize = sizeof(stClientAddr);			/* 클라이언트 주소 구조체의 크기 */
	int nWriteLength = 0;
	struct epoll_event stEvent = {0, };
	struct epoll_event *pstEpollEvent[MAXCLIENT] = {0, };
	//struct epoll_event stEpollEvent[MAXCLIENT] = {0, };
	int nEpollFileDescriptor = -1;
	int nEventCnt = 0;
	int nIndex = 0;
 
	/* signal 처리 */
	signal(SIGINT, signalHandlerServer);
 
	if (argc != 2)
	{
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}
 
	/* port 예외 처리 port 범위 */
	if(atoi(argv[1]) < 1024 || atoi(argv[1]) > 49151)
	{
		errHandle(errno, "port 사용하지 않는 포트입니다.\n");
		exit(1);
	}
	else
	{
		nPort = atoi(argv[1]);
	}
 
	printf("서버 연결 중입니다.\n");
	g_nServerSocket = serverSocket(nPort);
 
	/* server socket 예외 처리 */
	if(g_nServerSocket < 0)
	{
		errHandle(errno, "socket() error \n");
		exit(1);
	}
 
	nEpollFileDescriptor = epoll_create(EPOLLSIZE);
 
	if(nEpollFileDescriptor < 0)
	{
		errHandle(errno, "epoll file error \n");
		close(g_nServerSocket);
		g_nServerSocket = -1;
		exit(1);
	}
 
	/* calloc() 메모리 할당 및 초기화 */
	if((pstEpollEvent = calloc(EPOLLSIZE, sizeof(struct epoll_event))) == NULL)
	{
		errHandle(errno, "할당되지 않았습니다. \n");
		close(g_nServerSocket);
		g_nServerSocket = -1;
		exit(1);
		//close(nEpollFileDescriptor);
		//nEpollFileDescriptor = -1;
	}
 
	setNonblockSocket(g_nServerSocket);						/* server socket 에서 비동기 IO 설정 */
	stEvent.events = EPOLLIN | EPOLLRDHUP | EPOLLET;	/* event 발생 시 알림 */
	stEvent.data.fd = g_nServerSocket;						/* server socket 추가 */
 
	/* server socket 상태 변화를 nEpollFileDescriptor 통해 알 수 있다. */
	/* 예외 처리 추가 */
	if(epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_ADD, g_nServerSocket, &stEvent) < 0)
	{
		errHandle(errno, "server socket 상태 변화를 nEpollFileDescriptor 통해 관찰할 수 없습니다.");\
		close(nEpollFileDescriptor);
		nEpollFileDescriptor = -1;
		close(g_nServerSocket);
		g_nServerSocket = -1;
		exit(1);
	}
 
	while(1)
	{
		/* nEpollFileDescriptor 의 사건 발생 시 pstEpollEvent 에 fd 채운다. */
		nEventCnt = epoll_wait(nEpollFileDescriptor, pstEpollEvent, EPOLLSIZE, -1);
 
		/* neventCnt 예외 처리 */
		if(nEventCnt < 0)
		{
			errHandle(errno, "epoll wait error");
			break;
		}
		else if(nEventCnt == 0)
		{
			break;
		}
 
		/* event 발생 횟수 출력 */
		printf("return epoll 발생 \n");
 
		for(nIndex = 0; nIndex < nEventCnt; nIndex++)
		{
			if(pstEpollEvent[nIndex].data.fd == g_nServerSocket)
			{
				g_nClientSocket = accept(g_nServerSocket, (struct sockaddr*) &stClientAddr, &uClientAddrSize);
 
				for(g_nClientCount = 0; g_nClientCount < MAXCLIENT; g_nClientCount++)
				{
					g_nClient[g_nClientCount++] = g_nClientSocket;
				}
 
				//g_nClientSocket[nClientCount++] = g_nClientSocket[MAXCLIENT];		/* client socket 배열에 */
 
				//g_nClientSocket[nClientCount++] = g_nClientSocket[MAXCLIENT];
 
				/* client socket 예외 처리 client 배열 */
				if(g_nClient[g_nClientCount] < 0)
				{
					errHandle(errno, "accept error");
					continue;
				}
				else
				{
					printf("클라이언트 접속 IP : %s\n", inet_ntoa(stClientAddr.sin_addr));
					printf("accept() client 접속 요청 수락");
				}
 
				setNonblockSocket(g_nClient[g_nClientCount]);		/* client 소켓 넌블로킹으로 */
				stEvent.events = EPOLLIN | EPOLLRDHUP | EPOLLET;		/* event */
				//stEvent.events = EPOLLIN | EPOLLET;
				stEvent.data.fd = g_nClient[g_nClientCount];						/* client socket */
				/* epoll_ctl() 로 pstEpollEvent 상태 변화를 nEpollFileDescriptor로 확인 */
				if(epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_ADD, g_nClient[g_nClientCount], &stEvent) < 0)
				{
					errHandle(errno, "client socket 상태 변화가 되지 않았습니다.");
					close(g_nClientSocket[g_nClientCount]);
					g_nClientSocket[g_nClientCount] = {0, };
					continue;
				}
				printf("연결된 클라이언트 : %d\n", g_nClientSocket[g_nClientCount]);
			}
			else
			{
				//nReadLength = read(pstEpollEvent[nIndex].data.fd, szMsg, SIZEBUFFER);
				nReadLength = read(pstEpollEvent[nIndex].data.fd, szMsg, SIZEBUFFER);
 
				printf("받은 메시지 %s\n", szMsg);
 
				if(nReadLength == 0)
				{
					//epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, &stEvent);
					//close(nEpollFileDescriptor);
					//nEpollFileDescriptor = -1;
 
					epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, &stEvent);
					close(pstEpollEvent[nIndex].data.fd);
					printf("연결 종료된 클라이언트 %d\n", pstEpollEvent[nIndex].data.fd);
 
					/*
					epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, &stEvent);
					close(pstEpollEvent[nIndex].data.fd);
					printf("연결 종료된 클라이언트 %d\n", pstEpollEvent[nIndex].data.fd);
					*/
					continue;
					//break;
				}
				else if(nReadLength < 0)
				{
					errHandle(errno, "read error \n");
 
					if(errno != EAGAIN)			/* EAGAIN 제외한 예외 처리 추가 */
					{
						errHandle(errno, "error \n");
						epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, &stEvent);
						close(pstEpollEvent[nIndex].data.fd);
						continue;
					}
					else if(errno == EAGAIN)	/* EAGAIN 예외 처리 */
					{
						errHandle(errno, "error \n");
						epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, &stEvent);
						close(pstEpollEvent[nIndex].data.fd);
						continue;
					}
 
 
					/* 에러 예외 처리 추가 error */
					/*
					if(errno == EAGAIN || errno == EINVAL || errno == EBADF || errno == EEXIST || errno == ELOOP || 
						errno == ENOENT || errno == ENOMEM || errno == ENOSPC || errno == EPERM)	/* error 예외 처리 */
					/*
					{
						errHandle(errno, "error \n");
						epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, &stEvent);
						//epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, &stEvent);
						//close(nEpollFileDescriptor);
						//nEpollFileDescriptor = -1;
						close(pstEpollEvent[nIndex].data.fd);
						break;
					}
					*/
				}
				else
				{
					for(nIndex=0; nIndex < g_nClientCount; nIndex++)//클라이언트 개수만큼
					{
						nWriteLength = write(pstEpollEvent[nIndex].data.fd, szMsg, nReadLength);		//클라이언트들에게 메시지를 전달한다.
					}
 
					if(nWriteLength < 0)
					{
						errHandle(errno, "write error \n");
						epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, &stEvent);
						//close(nEpollFileDescriptor);
						//nEpollFileDescriptor = -1;
						close(pstEpollEvent[nIndex].data.fd);
						continue;
					}
 
					memset(szMsg, 0, sizeof(szMsg));
				}
			}
 
			for(nIndex = 0; nIndex < g_nClientCount; nIndex++)			//배열의 갯수만큼
			{
				if(g_nClientSocket == g_nClient[nIndex])	//만약 현재 clientSock값이 배열의 값과 같다면
				{
					while(nIndex++ < g_nClientCount - 1)				//클라이언트 개수 만큼
					{
						g_nClient[nIndex] = g_nClient[nIndex + 1];	//앞으로 땡긴다.
					}
					continue;
				}
			}
 
		}
	}
 
 
	free(pstEpollEvent);
	pstEpollEvent = NULL;
	close(nEpollFileDescriptor);
	nEpollFileDescriptor = -1;
	nClientCount--;				//클라이언트 개수 하나 감소
	//close(g_nClientSocket);
	//g_nClientSocket = -1;
	close(g_nServerSocket);
	g_nServerSocket = -1;
	printf("연결이 끊어졌습니다. \n");
	return 0;
}
 
void signalHandlerServer(int nSignal)
{
	char szMessage[SIZEBUFFER] = {0,};
 
	if (nSignal == SIGINT)
	{
		fputs("종료하시겠습니까?(y 입력) : ", stdout);
		fgets(szMessage, SIZEBUFFER, stdin);
		if(!strcasecmp(szMessage, "y\n"))
		{
			if(g_nClientSocket[nClientCount] >= 0)
			{
				close(g_nClient[nClientCount]);
				//close(g_nClientSocket[MAXCLIENT]);
				g_nClient[nClientCount] = {0, };
				printf("client socket 종료되었습니다.\n");
			}
 
			if(g_nServerSocket >= 0)
			{
				close(g_nServerSocket);
				g_nServerSocket = -1;
				printf("server socket 종료되었습니다.\n");
			}
			exit(0);
		}
	}
}
 
int setNonblockSocket(int nFileDescriptor)
{
	int nFlag = fcntl(nFileDescriptor, F_GETFL, 0);
 
	/* nFlag 예외 처리 */
	if(nFlag < 0)
	{
		errHandle(errno, "flag error");
		exit(1);
	}
 
	fcntl(nFileDescriptor, F_SETFL, nFlag | O_NONBLOCK);
 
	return 0;
}

client

#include "libDefine.h"
 
void signalHandlerClient(int nSignal);
 
//int g_nClientSocket = -1;
int g_nClientSocket[MAXCLIENT] = {0, };
int g_nClientCount = 0;
 
//int g_nClientSocket[EPOLLSIZE] = {0, };
 
int main(int argc, char *argv[])
{
	int nPort = -1;
	char *pszAddr = NULL;					/* ip 문자 입력받을 포인터 변수 */
	char szMsg[SIZEBUFFER + 1] = {0,};	/* 서버에 보낼 메시지를 저장할 문자열 버퍼 */
	int nReadLength = 0;						/* 송수신 메시지의 문자열 길이 */
	int nWriteLength = 0;
	//int nEpollFileDescriptor = -1;
	//struct epoll_event *pstEpollEvent = {0, };
	//struct epoll_event stEpollEvent[EPOLLSIZE] = {0, };
	//struct epoll_event stEvent = {0, };
	//int nIndex = 0;
	//int nReady = 0;
 
	signal(SIGINT, signalHandlerClient);
 
	/* port */
	if (argc != 3)
	{
		printf("usage : %s <IP> <port> \n", argv[0]);
		exit(1);
	}
 
	pszAddr = argv[1];
 
	/* port 사용 범위 예외 처리 */
	if(atoi(argv[2]) < 1024 || atoi(argv[2]) > 49151)
	{
		errHandle(errno, "port incorrect \n");
		exit(1);
	}
	else
	{
		nPort = atoi(argv[2]);
	}
 
	g_nClientSocket = clientSocket(nPort, pszAddr);
 
	if(g_nClientSocket < 0)
	{
		errHandle(errno, "socket() error \n");
		exit(1);
	}
 
	while (1)
	{
		memset(szMsg, 0, sizeof(szMsg));
 
		fputs("입력 메시지(Q는 종료, 버퍼(1024)까지 입력할 수 있습니다.) : ", stdout);
		fgets(szMsg, sizeof(szMsg), stdin);
 
		if(fgets(szMsg, sizeof(szMsg), stdin) == )
 
		//szMsg[strlen(szMsg) - 1] = '\0';
 
		/*
		if(fgets(szMsg, sizeof(szMsg), stdin) == NULL)
		{
			fputs("입력 메시지 ", stdout);
			fgets(szMsg, sizeof(szMsg), stdin);
			fputs("입력 ", stdout);
		}
		*/
 
		if(!strcasecmp(szMsg, "q\n"))
		{
			close(g_nClientSocket);
			g_nClientSocket = -1;
			break;
		}
 
		if((nWriteLength = write(g_nClientSocket, szMsg, strlen(szMsg))) < 0)
		{
			errHandle(errno, "write error \n");
			close(g_nClientSocket);
			g_nClientSocket = -1;
			exit(1);
		}
 
		/*---Wait for data---*/
 
		//nReady = epoll_wait(nEpollFileDescriptor, pstEpollEvent, EPOLLSIZE, 1000);
		/*
		for(nIndex = 0; nIndex < nReady; nIndex++)
		{
			if(pstEpollEvent[nIndex].events & EPOLLIN)
			{
				printf("data %d\n", pstEpollEvent[nIndex].data.fd);
				memset(szMsg, 0, sizeof(szMsg));
				read(g_nClientSocket, szMsg, sizeof(szMsg));
				printf("Received %s\n", szMsg);
			}
			else if(pstEpollEvent[nIndex].events & EPOLLRDHUP)
			{
				printf("connect close %d\n", pstEpollEvent[nIndex].data.fd);
				epoll_ctl(nEpollFileDescriptor, EPOLL_CTL_DEL, pstEpollEvent[nIndex].data.fd, NULL); // 종료된 클라이언트들의 소켓 디스크립터
				close(pstEpollEvent[nIndex].data.fd);
				printf("closed client: %d \n", pstEpollEvent[nIndex].data.fd);
			}
		}
		*/
		//num_ready = epoll_wait(epfd, events, MAX_EPOLL_EVENTS, 1000/*timeout*/);
 
		memset(szMsg, 0, sizeof(szMsg));
 
		if((nReadLength = read(g_nClientSocket, szMsg, nWriteLength)) < 0)
		{
			errHandle(errno, "read error \n");
			close(g_nClientSocket);
			g_nClientSocket = -1;
			exit(1);
		}
 
		szMsg[nReadLength] = 0;
		printf("서버로 받은 메시지 : %s\n", szMsg);
	}
	return 0;
}
 
void signalHandlerClient(int nSignal)
{
	char szMessage[SIZEBUFFER] = {0,};
 
	if (nSignal == SIGINT)
	{
		fputs("종료하시겠습니까?(y 입력) : ", stdout);
		fgets(szMessage, SIZEBUFFER, stdin);
		if(!strcasecmp(szMessage, "y\n"))
		{
			if(g_nClientSocket >= 0)
			{
				close(g_nClientSocket);
				g_nClientSocket = -1;
				printf("연결 종료되었습니다.\n");
			}
			exit(0);
		}
	}
}

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.