- 서버
//#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 개가 넘어서는지 확인할 수 있다.
'Engineering > Network' 카테고리의 다른 글
[kafka] NotLeaderOrFollowerException 에러 확인 (0) | 2022.07.13 |
---|---|
dhcp 인터페이스를 static 으로 변경 (0) | 2018.11.23 |
maillog 로그중에 NOQUEUE: SYSERR(apache): can not chdir(/var/spool/clientmqueue/): Permission denied (0) | 2012.01.10 |
로컬호스트의 열려진 포트(바인딩하지 않은 포트) 알아오는 간단한 소스 (0) | 2011.11.16 |
sqlplus 로 oracle 접속시 tcpdump 패킷 분석 (0) | 2011.03.31 |