/*
WINDOWS,SOCKET,SELECT,SERVER,TCP
WINDOWS,SOCKET,SELECT,SERVER,TCP
WINDOWS,SOCKET,SELECT,SERVER,TCP,MULTI CHAT
WINDOWS,SOCKET,SELECT,SERVER,TCP,MULTI CHAT
WINDOWS,SOCKET,SELECT,SERVER,TCP,MULTI CHAT
WINDOWS,SOCKET,SELECT,SERVER,TCP,MULTI CHAT
*/
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <winsock2.h>
#include <string.h>
#define MAXLINE 512
#define MAX_SOCK 64
#define bzero(b,len) (memset(b,0,len))
#define bcopy(b1,b2,len) (memcpy(b1,b2,len))
char *escapechar = "exit";
char send_calc_msg[MAXLINE+1];
//EXTERN LINK VARIABLE
char input[MAXLINE+1];
int maxfdp1;
int g_num_chat = 0;
int client_s[MAX_SOCK];
//STATIC LINK
static int getmax(int);
static void removeclient(int);
static int getdottedipaddr(int sd, struct sockaddr_in *addr);
//EXTERN LINK(calc_server.c)
int calculation_socket(char send_calc_msg[MAXLINE+1]);
//EXTERN LINK(pushcall.c)
int pushcall(void);
//EXTERN LINK(common.c)
int GetDate();
int GetTime();
int main(int argc, char *argv[])
{
char rline[MAXLINE+1], send_calc_msg[MAXLINE+1];
char *welcome_msg = "Connected to Server, Welcome!!!!!!!\n";
char tmp[1024];
int ii, kk, nn;
int client_fd, clilen, rc;
fd_set read_fds;
WSADATA wsadata;
SOCKET hservsock;
SOCKADDR_IN client_addr, server_addr;
if (argc != 2) {
printf("usage : %s port\n", argv[0]);
return(-1);
}
//The Windows Sockets WSAStartup function initiates use of WS2_32.DLL by a process.
//The WSAStartup function must be the first Windows Sockets function called by an application or DLL.
//It allows an application or DLL to specify the version of Windows Sockets required and to retrieve details of the specific Windows Sockets implementation.
//The application or DLL can only issue further Windows Sockets functions after a successfully calling
if(WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
{
printf("Load Winsock 2.2 DLL Error\n");
return(-9);
}
printf(">>>>>1. wsastartup succ!!(%d)(%d)\n", GetDate(), GetTime());
hservsock=socket(PF_INET, SOCK_STREAM, 0);
if(hservsock==INVALID_SOCKET)
{
printf("socket() error\n");
return(-8);
}
printf(">>>>>2. socket succ!!(%d)(%d)\n", GetDate(), GetTime());
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(hservsock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
printf("server: can't bind local address.\n");
return(-3);
}
printf(">>>>>3. bind succ!!(%d)(%d)\n", GetDate(), GetTime());
listen(hservsock, 5); /* backlog = 5 */
printf(">>>>>4. listen succ!!(%d)(%d)\n", GetDate(), GetTime());
maxfdp1 = hservsock + 1;
printf(">>>>>5. main ok!!!!!!!(%d)(%d)\n", GetDate(), GetTime());
printf(">>>>>5. main ok!!!!!!!(%d)(%d)\n", GetDate(), GetTime());
printf(">>>>>5. main ok!!!!!!!(%d)(%d)\n", GetDate(), GetTime());
while (1)
{
//initialization with all user(send), server(receive)
FD_ZERO(&read_fds);
//FD_SET은 관찰을 할 소켓들을 등록하는 변수입니다.
//소켓이 새로 만들어지고 select()함수를 통해 관찰을 하고 싶다면 fd_set변수에 소켓을 등록해야 합니다.
//set register reference value with all user(send), server(receive)
FD_SET(hservsock, &read_fds);
for (ii=0; ii < g_num_chat; ii++)
{
FD_SET(client_s[ii], &read_fds);
}
//maxfdp1 variavle values re-calculation
maxfdp1 = getmax(hservsock) + 1;
/*wait & response, all client & server */
/*wait & response, all client & server */
/*wait & response, all client & server */
/*wait & response, all client & server */
if (select(maxfdp1, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0)
{
printf("server: select error.\n");
break;
}
//1. SELECT call and search change socket-filediscriptor
//2. CHANGED socket-filediscriptor, find socket-filediscriptor, send, recv, accept function call
//3. FD_ISSET(hservsock, &read_fds) is accept function calling
//4. FD_ISSET(client_s[ii], &read_fds) is recv, send function calling
if (FD_ISSET(hservsock, &read_fds))
{
//관찰의 대상은 server socket도 대상이 됩니다.
//기존에 존재하는 클라이언트가 아닌 새로운 클라이언트의 접속요청을 받앗을때에 해당됩니다.
//select target is two groups
//1. server socket
//2. client socket(when multi, loop is needed)
//1 user connected with server
clilen = sizeof(client_addr);
client_fd = accept(hservsock, (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++;
printf("1. server: accept ok.cient fd[%d],all user cnt[%d]-------------------------\n",
client_fd, g_num_chat);
printf("1. server: accept ok.cient fd[%d],all user cnt[%d]-------------------------\n",
client_fd, g_num_chat);
printf("1. server: accept ok.cient fd[%d],all user cnt[%d]-------------------------\n",
client_fd, g_num_chat);
/*welcome message*/
printf("2. server: send [welcome message] ok.--------------------------------------\n");
send(client_fd, welcome_msg, strlen(welcome_msg), 0);
if (getdottedipaddr(client_fd, &client_addr) > -1)
printf("3. %d number additional(IP: %s)\n", g_num_chat, inet_ntoa(client_addr.sin_addr));
else
printf("3. %d number additional\n", g_num_chat);
}
/*ABOUT SERVER CONNECTED, g_num_chat수에 대해 RECEIVE 메세지가 있는지 ALL 조사해서,
g_num_chat수만큼 다시 해당메세지를 ALL SENDING.*/
for (ii=0; ii<g_num_chat; ii++)
{
//client_s[ii]에 read_fds의 값이 설정되어 있으면 0이 아닙니다.
if (FD_ISSET(client_s[ii], &read_fds))
{
printf("4. server: recv ok,client_s[%.5d][%d].------------------------------------------\n",
ii+1, client_s[ii]);
if ((nn = recv(client_s[ii], rline, MAXLINE, 0)) <= 0)
{
removeclient(ii); /* abrupt exit *//* abrupt exit *//* abrupt exit *//* abrupt exit */
continue;
}
rline[nn] = 0x00;
if (strstr(rline, escapechar) != NULL)
{
removeclient(ii); /* abrupt exit *//* abrupt exit *//* abrupt exit *//* abrupt exit *//* abrupt exit */
continue;
}
//according to recv msg, logic execute
//according to recv msg, logic execute
//according to recv msg, logic execute
if(strstr(rline, "GOOGLE") != NULL) //unique user response
{
rc = pushcall();
if(rc)
{
//ERROR
}
memset(send_calc_msg,0x00,sizeof(send_calc_msg));
strcpy(send_calc_msg, "google pushcall succ!!\n");
send(client_s[ii], send_calc_msg, strlen(send_calc_msg), 0);
}
if(strstr(rline, "help") != NULL) //unique user response
{
memset(tmp,0x00,sizeof(tmp));
strcat(tmp, "1. GOOGLE\n");
strcat(tmp, "2. calc>>\n");
strcat(tmp, "3. msg>>\n");
send(client_s[ii], tmp, strlen(tmp), 0);
}
else if(strstr(rline, "calc>>") != NULL) //all user response
{
memset(send_calc_msg,0x00,sizeof(send_calc_msg));
memset(input,0x00,sizeof(input));
sprintf(input, "%s", strstr(rline, "calc>>") + strlen("calc>>"));
rc = calculation_socket(send_calc_msg);
if(rc)
{
//ERROR
}
for (kk=0; kk<g_num_chat; kk++)
{
printf("5. server: send ok,client_s[%.5d][%d]-------------------------------------------\n", kk+1, client_s[kk]);
if(client_s[kk] == client_s[ii])
{
send(client_s[kk], send_calc_msg, strlen(send_calc_msg), 0);
}
else
{
memset(tmp,0x00,sizeof(tmp));
memcpy(tmp, rline, nn);
strcat(tmp, "other user request & response:");
strcat(tmp, send_calc_msg);
send(client_s[kk], tmp, strlen(tmp), 0);
}
}
}
else if(strstr(rline, "msg>>") != NULL) //all user response
{
memset(tmp,0x00,sizeof(tmp));
sprintf(tmp, "%s", strstr(rline, "msg>>") + strlen("msg>>"));
for (kk=0; kk<g_num_chat; kk++)
{
printf("5. server: send ok,client_s[%.5d][%d]-------------------------------------------\n", kk+1, client_s[kk]);
if(client_s[kk] == client_s[ii])
{
send(client_s[kk], tmp, strlen(tmp), 0);
}
else
{
send(client_s[kk], tmp, strlen(tmp), 0);
}
}
}
if (getdottedipaddr(client_fd, &client_addr) > -1)
{
printf("6. IP:(%s),message:%s", inet_ntoa(client_addr.sin_addr), rline);
}
else
{
printf("6. message:%s", rline);
}
}
}
} /* while */
//The WSACleanup function terminates use of the Winsock 2 DLL (Ws2_32.dll).
//The WSACleanup function terminates use of the Winsock 2 DLL (Ws2_32.dll).
//The WSACleanup function terminates use of the Winsock 2 DLL (Ws2_32.dll).
rc = WSACleanup();
if(rc == WSANOTINITIALISED)
{
printf(">>error::A successful WSAStartup call must occur before using this function.\n");
}
else if(rc == WSAENETDOWN)
{
printf(">>error::The network subsystem has failed.\n");
}
else if(rc == WSAEINPROGRESS)
{
printf(">>error::A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.\n");
}
closesocket(hservsock);
}
void removeclient(int indx)
{
struct sockaddr_in client_addr;
if (getdottedipaddr(client_s[indx], &client_addr) > -1)
{
printf("\nserver>>removeclient>>1 number expired!!(IP: %s).", inet_ntoa(client_addr.sin_addr));
}
else
{
printf("\nserver>>removeclient>>1 number expired!!.");
}
closesocket(client_s[indx]);
if (indx != g_num_chat-1)
{
client_s[indx] = client_s[g_num_chat-1];
}
g_num_chat--;
printf("\nserver>>removeclient>>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;
}