/*
LINUX,SERVER,SELECT(RECV),SELECT(SEND)
LINUX,SERVER,SELECT(RECV),SELECT(SEND)
LINUX,SERVER,SELECT(RECV),SELECT(SEND)
LINUX,SERVER,SELECT(RECV),SELECT(SEND)
LINUX,SERVER,SELECT(RECV),SELECT(SEND)
LINUX,SERVER,SELECT(RECV),SELECT(SEND)
LINUX,SERVER,SELECT(RECV),SELECT(SEND)
LINUX,SERVER,SELECT(RECV),SELECT(SEND)
*/
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <string.h>
#define MAXLINE 512
#define MAX_SOCK 64
char *escapechar = "exit";
int maxfdp1;
int g_num_chat = 0;
int s;
int client_s[MAX_SOCK];
static int getmax(int);
static void removeclient(int);
static int getdottedipaddr(int sd, struct sockaddr_in *addr);
static void my_signal(int signo);
int main(int argc, char *argv[])
{
char rline[MAXLINE+1];
char *start = "Connected to chat-server\n";
int i, j, n;
int client_fd, clilen;
fd_set read_fds;
struct sockaddr_in client_addr, server_addr;
if (argc != 2) {
printf("usage : %s port\n", argv[0]);
return(-1);
}
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
printf("can't open stream socket.");
return(-2);
}
bzero((char *)&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(atoi(argv[1]));
if (bind(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
printf("Server: Can't bind local address.\n");
return(-3);
}
if (signal(SIGINT, my_signal) == SIG_ERR) { /* Ctrl+C */
printf("Server: signal(SIGINT) error\n");
return(-4);
}
if (signal(SIGTERM, my_signal) == SIG_ERR) { /* software termination */
printf("Server: signal(SIGTERM) error\n");
return(-5);
}
if (signal(SIGQUIT, my_signal) == SIG_ERR) { /* Ctrl+\ */
printf("Server: signal(SIGQUIT) error\n");
return(-6);
}
listen(s, 5); /* backlog = 5 */
maxfdp1 = s + 1;
while (1)
{
FD_ZERO(&read_fds);
FD_SET(s, &read_fds);
for (ii=0; ii < g_num_chat; ii++)
{
FD_SET(client_s[ii], &read_fds);
}
maxfdp1 = getmax(s) + 1; /* maxfdp1 재 계산 */
/*wait & response*/
/*wait & response*/
/*wait & response*/
/*wait & response*/
/*wait & response*/
/*wait & response*/
/*wait & response*/
/*wait & response*/
if (select(maxfdp1, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0)
{
printf("select error.\n");
break;
}
if (FD_ISSET(s, &read_fds))
{
clilen = sizeof(client_addr);
client_fd = accept(s, (struct sockaddr *)&client_addr, &clilen);
if (client_fd == -1)
{
printf("server: accept error\n");
break;
}
client_s[g_num_chat] = client_fd;
g_num_chat++;
/*welcome message*/
/*welcome message*/
/*welcome message*/
/*welcome message*/
/*welcome message*/
/*welcome message*/
/*welcome message*/
/*welcome message*/
send(client_fd, start, strlen(start), 0);
if (getdottedipaddr(client_fd, &client_addr) > -1)
printf("%d number additional(IP: %s)\n", g_num_chat, inet_ntoa(client_addr.sin_addr));
else
printf("%d number additional\n", g_num_chat);
}
for (ii=0; ii<g_num_chat; ii++)
{
if (FD_ISSET(client_s[ii], &read_fds))
{
if ((n = recv(client_s[ii], rline, MAXLINE, 0)) <= 0)
{
removeclient(ii); /* abrupt exit *//* abrupt exit *//* abrupt exit *//* abrupt exit */
continue;
}
rline[n] = '\0';
if (strstr(rline, escapechar) != NULL)
{
removeclient(ii); /* abrupt exit *//* abrupt exit *//* abrupt exit *//* abrupt exit *//* abrupt exit */
continue;
}
for (kk=0; kk<g_num_chat; kk++)
{
send(client_s[kk], rline, n, 0);
}
if (getdottedipaddr(client_fd, &client_addr) > -1)
printf("IP: %s -> %s", inet_ntoa(client_addr.sin_addr), rline);
else
printf("%s", rline);
}
}
} /* while */
my_signal(SIGIO);
}
void removeclient(int indx)
{
struct sockaddr_in client_addr;
if (getdottedipaddr(client_s[indx], &client_addr) > -1)
printf("1 number expired!!(IP: %s).", inet_ntoa(client_addr.sin_addr));
else
printf("1 number expired!!.");
close(client_s[indx]);
if (indx != g_num_chat-1) client_s[indx] = client_s[g_num_chat-1];
g_num_chat--;
printf("now number = %d\n", g_num_chat);
}
int getmax(int k) {
int max = k;
int r;
for (r=0; r < g_num_chat; r++)
{
if (client_s[r] > max) max = client_s[r];
}
return max;
}
/* 소켓에 연결된 상대방 주소를 알아낸다 */
int getdottedipaddr(int sd, struct sockaddr_in *addr) {
struct sockaddr_in client_addr;
int len, r;
len = sizeof(client_addr);
if ((r = getpeername(sd, (struct sockaddr *)&client_addr, &len)) == 0)
{
*addr = client_addr;
}
return r;
}
/* 시그널 처리 함수 정의 */
void my_signal(int signo)
{
int ii;
/* 대부분의 시그널(SIGILL과 SIGTRAP 은 제외)에 대한 처리 함수는 시그널이 포작된 후
즉시 재지정된다. 이것은 프로세스가 시그널의 처리 함수를 잊어버리고, 다음에 시그널이
도착하면 묵시적 처리함수인 SIG_DFL 을 수행하는 것을 의미한다.
이것은 특히 사용자가 인터럽트키를 여러번 누를 수도 있는 대화명 프로그램에서 문제가 된다
그러므로 시그널 함수가 호출되자 마자 SIGINT 시그널을 무시한다 */
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
close(s);
for (ii=0; ii < g_num_chat; ii++)
{
close(client_s[ii]);
}
exit(0);
}
/*----------------------------------------------------------------------------------------------------
socket function : accept
1. 소켓에 연결을 받아들인다.
#include <sys/types.h>
#include <sys/socket.h>
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
2. 설명
accept() 함수는 연결지향 소켓 타입 (SOCK_STREAM, SOCK_SEQPACKET, SOCK_RDM)에 사용된다.
이것은 아직 처리되지 않은 연결들이 대기하고 있는 큐에서 제일 처음 연결된 연결을 가져와서 새로운 연결된 소켓을 만든다.
그리고 소켓을 가르키는 파일 지정자를 할당하고 이것을 리턴한다.
인자 s 는 socket() 로 만들어진 end-point(듣기 소켓)을 위한 파일지정자이다.
인자 addr 는 sockaddr 구조체에 대한 포인터이다.
연결이 성공되면 이 구조체를 채워서 되돌려 주게 되고,
우리는 이구조체의 정보를 이용해서 연결된 클라이언트의 인터넷 정보를 알아낼수 있다. addrlen 인자는 addr의 크기 이다.
만약 미결인 연결이 큐에 존재하지 않고, 소켓이 비봉쇄가 아니라면 accept 는 연결이 존재할때까지 해당영역에서 봉쇄된다.
비봉쇄 소켓일경우에는 errno 로 EAGAIN 을 설정하고 바로 리턴한다.
3. 반환값
에러시 -1이 반환된다. 성공한다면 받아들인 소켓을 위한 파일지정번호 (0보다 큰)을 반환한다.
---------------------------------*/
'통신 > SELECT(TCP)' 카테고리의 다른 글
WINDOWS,SERVER,SELECT(FILE RECV),BASIC(SEND) (0) | 2019.10.29 |
---|---|
WINDOWS,CLIENT,THREAD(FILE READ SEND),BASIC(RECV) (0) | 2019.10.29 |
Makefile(win_calc_server: win_calc_server.o pushcall.o common.o calc_server.o) (0) | 2019.10.29 |
Windows,client,tcp,basic(recv),thread(send) (0) | 2019.10.29 |
Windows,server,tcp,select(recv),select(send),multi-client (0) | 2019.10.29 |