select
A server program can handle multiple sockets using select()
.
select(maxfd, &rset, NULL, NULL, NULL);
fd_set rset; // rset is a bit vector of size 1024 bit
FD_ZERO(&rset); // initialize rset with 0
FD_SET(3, &rset); // set bit 3 of rset to 1
FD_CLR(3, &rset); // reset bit 3 of rset to 0
FD_ISSET(3, &rset); / return true if bit 3 of rset is 1
select()
system calls2=accept(s1, ...); // waiting on socket s1 only (for SYN packet)
read(s2, ...); // waiting on socket s2 only (for data packet)
==>
select(..., &rset, ......); // waiting on all sockets marked in rset
for each socket "x" that has packet arrived(SYN, or data packet)
if it is SYN packet
s2 = accept(x, .....); // handle SYN packet
or if it is data packet
read(x, .....); // read the data and handle appropriately
.........
select()
.
select()
is better in the case when the clients need to talk to each other.
select()
since the server has to relay messages between clients.fork()
is better when the clients do not need to talk to each other.
fork()
since the clients do not need to talk to each other. FD_SET(3, &rset);
FD_SET(5, &rset);
FD_SET(21, &rset);
select(maxfd, &rset, NULL, NULL, NULL);
The server will wait for client packets from either one or multiple of socket 3, 5, and 21 in select()
. When packets from one or multiple of these sockets arrive, the select will return with active sockets (ones with packets arrived) marked 1 and non-active sockets (ones with no packet) reset to 0 in rset.
Therefore, after select()
, we can check which sockets had packets.
To use select()
:
set pset; // step 1
for(;;){
copy pset to rset; // step 2
Call select(); // step 3
//The active sockets (those where a packet has arrived) will be marked as 1 in
// rset; non-active sockets (where no packet has arrived) will be reset to 0.
for(all marked sockets){ // step 4
read the arrived data and handle them appropriately.
}
}
Without select()
, it is hard to read from multiple sockets at the same time.
read(3, buf, n); // reading packets from socket 3
read(5, buf, n); // reading from socket 5
read(21, buf, n); // reading from socket 21
We have to read each socket one by one, not at the same time.
fd_set rset, pset; // rset used in select(). pset remembers the sockets to monitor
FD_ZERO(&rset);
FD_ZERO(&pset); // all bits are zerorized in the beginning
// step 1. prepare pset
FD_SET(3, &pset);
FD_SET(5, &pset);
FD_SET(21, &pset); // we want to monitor socket 3, 5, and 21
for(;;){
// step 2. copy pset to rset
rset = pset; // pset remembers target socket numbers.
// setp 3. call select()
select(maxfd, &rset, NULL, NULL, NULL);
// step 4. now we check which sockets had packets
for(x=0; x<maxfd; x++){ // check each socket
if (FD_ISSET(x, &rset)){ // this socket has some packet
........handle this packet .........
}
}
}
A server communicates with multiple clients. When connected, the client and the server exchange messages as follows:
cli=>serv: ping
serv=>cli : pong
cli=>serv: pang
serv=>cli: pung
s = socket(...);
connect(s, server, ...);
write(s, "ping", 4);
read(s, buf, n); // read "pong"
write(s, "pang", 4);
read(s, buf, n); // read "pung"
close(s);
s1 = socket(...); // to accept connection
......bind, listen, .......
FD_SET(s1, &pset); // step 1. we have to monitor connection request packet
for(;;){
rset = pset; // step 2
select(maxfd, &rset, NULL, NULL, NULL); // step 3
for(x=0; x<maxfd; x++){ // step 4
if (FD_ISSET(x, &rset)){ // found active socket
if (x == s1){ // connection request on s1. new client has arrived.
s2 = accept(s1, .........); // create a new socket, s2, for this client
FD_SET(s2, &pset); // and remember s2 in pset for future monitoring
} else{ // must be a data packet from a client. follow the protocol.
handle_protocol(x, &pset);
}
}
}
}
................
void handle_protocol(int x, fd_set * pset){
...........
y=read(x, buf, n); // read data from socket x
buf[y]=0; // make it a string
if (strcmp(buf, "ping")==0)
write(x, "pong", 4);
else if (strcmp(buf, "pang")==0){
write(x, "pung", 4);
write(x, "protocol ended ok", 17);
close(x);
FD_CLR(x, &pset); // don't monitor this socket anymore
}
}
$ cp ../../linuxer1/cliping.c .
$ cp ../../linuxer1/servping.c .
^C
๋ก ๋น ์ ธ๋์๋ค.client์์ ์ฒซ๋ฒ์งธ ์ ๋ ฅ์ โpingโ์ด ์๋๋ผ โpangโ์ ์ ๋ ฅํจ์ผ๋ก์จ ํ๋กํ ์ฝ์ ์งํค์ง ์์์ ๋, server๊ฐ ์ค๋ฅ๋ฅผ ๋ฐํํ์ง ์๊ณ โpongโ์ ๋ฐํํ์๋ค.
state
๋ฐฐ์ด์ ์ ์ธํด ๊ฐ ์์ผ๋ณ ์ํ๋ฅผ ์ ์ฅํ์๋ค.
๊ทธ๋ฆฌ๊ณ ์์ผ์ด ์์ฑ๋ ๋, ์ํ๋ฅผ 1๋ก ์ด๊ธฐํํด์ฃผ์๋ค.
......
int maxfd = 50; // just monitor max 50 sockets
int state[maxfd]; // ex2 : ๊ฐ ์์ผ๋ณ ์ํ๋ฅผ ์ ์ฅํ๋ ๋ฐฐ์ด ์ ์ธ
......
// step 1. monitor conn req packet
FD_SET(s1, &pset);
for (i = 0; i < 20; i++)
{
......
for (x = 0; x < maxfd; x++)
{
if (FD_ISSET(x, &rset))
{
if (x == s1)
{
s2 = accept(s1, (struct sockaddr *)&cli_addr, &xx);
state[s2] = 1; // ex2 : ํด๋น ์์ผ์ ์ํ๋ฅผ 1๋ก ์ด๊ธฐํ
......
}
......
}
}
}
state
์ ์ํ์ ๋ฐ๋ผ ์ด๋ค ํ๋กํ ์ฝ์ ์คํ์ํฌ์ง๋ฅผ ๊ตฌ๋ถํ๊ณ , ๊ฐ๊ฐ์ ์ํฉ์ ํจ์๋ก ๊ตฌํํ์๋ค. (handle_state_1()
, handle_state_2()
) ๊ทธ๋ฆฌ๊ณ handle_protocol()
ํจ์๋ฅผ ์์ ํด์ฃผ์๋ค.
void handle_state_1(int x, fd_set *pset, char *buf, int state[])
{
if (strcmp(buf, "ping") == 0)
{ // if it is a ping
printf("received ping from socket %d\n", x);
write(x, "pong", 4); // send pong
printf("sent pong to socket %d\n", x);
}
else
{
printf("received other message from socket %d\n", x);
write(x, "Error! You should enter \"ping\". Try again!", 44); // send pong
printf("sent error message to socket %d\n", x);
}
state[x] = 2; // ex 2 : ์ํ ๊ฐ์ 2๋ก ์ค์
}
void handle_state_2(int x, fd_set *pset, char *buf, int state[])
{
if (strcmp(buf, "pang") == 0)
{ // it it is a pang
printf("received pang from socket %d\n", x);
write(x, "pung", 4); // send pung
printf("sent pung to socket %d\n", x);
close(x); // and stop the protocol
FD_CLR(x, pset); // no more monitoring on this socket
}
else
{
printf("received other message from socket %d\n", x);
write(x, "Error! You should enter \"pang\". Try again!", 44); // send pong
printf("sent error message to socket %d\n", x);
}
}
void handle_protocol(int x, fd_set *pset, int state[])
{
// we have a data packet in socket x. do protocol
int y;
char buf[50];
y = read(x, buf, 50); // read data
buf[y] = 0; // make it a string
if (state[x] == 1) // ex2 : ์ํ๊ฐ 1์ธ ๊ฒฝ์ฐ
handle_state_1(x, pset, buf, state);
else if (state[x] == 2) // ex2 : ์ํ๊ฐ 2์ธ ๊ฒฝ์ฐ
handle_state_2(x, pset, buf, state);
}
์คํ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
์ค๋ฅธ์ชฝ์ ๋ client๋ฅผ ์ฃผ๋ชฉํ์. ์์ชฝ์ client์์ ๋จผ์ โpingโ ๋์ โhelloโ๋ฅผ ์ ๋ ฅํ์ ๋ error message๋ฅผ ๋๋ ค๋ฐ์๋ค. ๊ทธ ํ, ์ ์์ ์ผ๋ก โpangโ์ ์ ๋ ฅํ์ ๋๋ ์ ์์ ์ผ๋ก โpungโ์ ๋๋ ค๋ฐ์๋ค.
์๋์ชฝ์ client์์๋ ๋จผ์ โpingโ์ ์๋ง๊ฒ ์ ๋ ฅํ์ ๋, ์ ์์ ์ผ๋ก โpongโ์ ๋๋ ค๋ฐ์๋ค. ๊ทธ ํ, โpangโ ๋์ โhiโ๋ฅผ ์ ๋ ฅํ์ ๋ error message๋ฅผ ๋๋ ค๋ฐ์๋ค.
client๊ฐ protocol์ ์ค์ํ์ง ์์์ ๊ฒฝ์ฐ ์ฐ๊ฒฐ์ close
ํ์๋ค.
int state[50]; // state of each client (state of each client socket)
// 1: the server is waiting for "ping" from this client
// 2: the server is waiting for "pang" from this client
...........
for(x=0;x<maxfd;x++){ // check all fd
if (FD_ISSET(x, &rset)){ // if we have packet in socket x
if (x==s1){ // if x is the connection accepting socket, we have a new client
// and we must have the connection request packet(SYN) at x
s2=accept(s1, ........); // now s2 is this client's socket
state[s2]=1; // init the state of this client.
// the server is expecting "ping" from this client
.............
}else{ // we must have the data packet at socket x
handle_protocol(x, &pset, state);
}
................
void handle_protocol(int x, fd_set *pset, int state[])
{
// we have data packet in socket x. state[x] shows the state of socket x.
// handle the protocol.
int y;
char buf[50];
y = read(x, buf, 50); // read the data
buf[y] = 0; // make it a string
if (state[x] == 1)
{ // the state of this socket is 1 meaning we are
// expecting "ping" from this socket
handle_state_1(x, pset, buf, state);
}
else if (state[x] == 2)
{ // expecting "pang"
handle_state_2(x, pset, buf, state);
}
}
void handle_state_1(int x, fd_set *pset, char *buf, int state[])
{
// socket x is in state 1. Expecting "ping" in buf. if we have ping, send "pong" and
// just update state[x]=2; otherwise send error message and disconnect the connection
if (strcmp(buf, "ping") == 0)
{ // yes we have "ping"
write(x, "pong", 4); // send pong to this client
state[x] = 2; // now we are waiting for "pang" from this client
}
else
{ // no we didn't receive "ping"
write(x, "protocol error", 14); // send err message to the client
close(x); // end the connection
FD_CLR(x, pset); // remove from the watch list.
// we don't monitor socket x any more
}
}
void handle_state_2(int x, fd_set *pset, char *buf, int state[])
{
// socket x is in state 2. we are expecting "pang" in buf. If we have "pang", send "pung"
// and close the connection. If we didnโt receive โpangโ, send โprotocol errorโ to the
// client and disconnect.
....................
}
cli=>serv: ping
serv=>cli: pong
cli=>serv: pang
serv=>cli: pung
cli=>serv: ping (final ping)
serv=>cli: protocol completed
Ex2์ฒ๋ผ handle_state_3
ํจ์๋ฅผ ์ถ๊ฐ๋ก ์ ์ํ์ฌ 3๋ฒ์งธ ์ํ๋ฅผ ๋ค๋ค์ฃผ์๋ค.
state[]
array to see which socket is ready to receive message.cli at socket 3 => serv: ping
serv => cli at socket 3 : pong
cli at socket 3 => serv: pang
serv => cli at socket 3 : pung. Protocol completed. Start chatting.
cli at socket 4 => serv: ping
serv => cli at socket 4 : pong
cli at socket 4 => serv: pang
serv => cli at socket 4 : pung. Protocol completed. Start chatting.
cli at socket 5 => serv: ping
serv => cli at socket 5 : pong
cli at socket 5 => serv: pang
serv => cli at socket 5 : pung. Protocol completed. Start chatting.
cli at socket 3 => serv: hello
serv => cli at socket 4, 5 : hello
cli at socket 4 => serv: hi
serv => cli at socket 3, 5: hi
.................
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#define SERV_TCP_PORT 8739
#define SERV_ADDR "165.246.38.151" //"192.168.50.122"
void handle_protocol(int x, fd_set *pset, int state[]);
void handle_state_1(int x, fd_set *pset, char *buf, int state[]);
void handle_state_2(int x, fd_set *pset, char *buf, int state[]);
void handle_state_3(int x, fd_set *pset, char *buf, int state[]);
int main()
{
int s1, s2, i, x, y;
struct sockaddr_in serv_addr, cli_addr;
char buf[50];
socklen_t xx;
printf("Hi, I am the server\n");
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = PF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_ADDR);
serv_addr.sin_port = htons(SERV_TCP_PORT);
// open a tcp socket
if ((s1 = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket creation error\n");
exit(1);
}
printf("socket opened successfully. socket num is %d\n", s1);
// bind ip
x = bind(s1, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (x < 0)
{
printf("binding failed\n");
exit(1);
}
printf("binding passed\n");
listen(s1, 5);
xx = sizeof(cli_addr);
// now start ping-pong-pang-pung
// pset remembers all sockets to monitor
// rset is the copy of pset passed to select
int maxfd = 50; // just monitor max 50 sockets
int state[maxfd]; // ex2 : ๊ฐ ์์ผ๋ณ ์ํ๋ฅผ ์ ์ฅํ๋ ๋ฐฐ์ด ์ ์ธ
fd_set rset, pset;
FD_ZERO(&rset); // init rset
FD_ZERO(&pset); // init pset
// step 1. monitor conn req packet
FD_SET(s1, &pset);
// and loop on select
for (i = 0; i < 20; i++)
{ // should be infinite loop in real life
rset = pset; // step 2
select(maxfd, &rset, NULL, NULL, NULL); // step 3
// now we have some packets
for (x = 0; x < maxfd; x++)
{ // check which socket has a packet
if (FD_ISSET(x, &rset))
{ // socket x has a packet
// s1 is a special socket for which we have to do "accept"
// otherwise do ping-pong-pang-pung
if (x == s1)
{ // new client has arrived
// create a socket for this client
s2 = accept(s1, (struct sockaddr *)&cli_addr, &xx);
state[s2] = 1; // ex2 : ํด๋น ์์ผ์ ์ํ๋ฅผ 1๋ก ์ด๊ธฐํ
printf("new cli at socket %d\n", s2);
FD_SET(s2, &pset); // and include this socket in pset
}
else
{ // data packet. do ping-pong-pang-pung protocol
handle_protocol(x, &pset, state);
}
}
}
}
}
void handle_state_1(int x, fd_set *pset, char *buf, int state[])
{
// socket x is in state 1. Expecting "ping" in buf. if we have ping, send "pong" and
// just update state[x]=2; otherwise send error message and disconnect the connection
if (strcmp(buf, "ping") == 0)
{ // if it is a ping
printf("client at socket %d => serv: ping\n", x);
write(x, "pong", 4); // send pong
printf("serv => client at socket %d: pong\n", x);
}
else
{
printf("client at socket %d => serv: other message\n", x);
write(x, "Error! You should enter \"ping\". Try again!", 44); // send pong
printf("serv => client at socket %d: Error! You should enter \"ping\". Try again!\n", x);
close(x); // ex 2-1 : and stop the protocol
FD_CLR(x, pset); // ex 2-1 : no more monitoring on this socket
}
state[x] = 2; // ex 2 : ์ํ ๊ฐ์ 2๋ก ์ค์
}
void handle_state_2(int x, fd_set *pset, char *buf, int state[])
{
// socket x is in state 2. we are expecting "pang" in buf. If we have "pang", send "pung"
// and close the connection. If we didnโt receive โpangโ, send โprotocol errorโ to the
// client and disconnect.
if (strcmp(buf, "pang") == 0)
{ // it it is a pang
printf("client at socket %d => serv: pang\n", x);
write(x, "pung. Process completed. Start chatting.", 40); // send pung
printf("serv => client at socket %d: pung. Process completed. Start chatting.\n", x);
}
else
{
printf("client at socket %d => serv: %s\n", x, buf);
write(x, "Error! You should enter \"pang\". Try again!", 44); // send pong
printf("serv => client at socket %d: Error! You should enter \"pang\". Try again!\n", x);
close(x); // and stop the protocol
FD_CLR(x, pset); // no more monitoring on this socket
}
state[x] = 3; // ex 3 : ์ํ ๊ฐ์ 3์ผ๋ก ์ค์
}
void handle_state_3(int x, fd_set *pset, char *buf, int state[]) // ์ฑํ
์ก์์ ์ด ๊ฐ๋ฅํ ์ํ
{
int i;
char msg[100];
sprintf(msg, "msg from cli %d : %s\n", x, buf); // ๋ฉ์ธ์ง์ ์ก์ ์ ๊ธฐ์ฌ (์์ผ๋ฒํธ ์ด์ฉ)
for (i = 0; i < 50; i++) // ์ต๋ 50๊ฐ ์์ผ๊น์ง monitor
{
if (state[i] >= 3 && i != x) // ์์ผ์ ์ํ๊ฐ 3์ด์์ด๋ฉด์ ์์ ์ด ์๋ ๋
{
// write(i, buf, strlen(buf)); // ๋ฉ์ธ์ง ์ ์ก
// printf("serv => client at socket %d : %s\n", i, buf);
write(i, msg, strlen(msg)); // ๋ฉ์ธ์ง ์ ์ก
}
}
state[x]++;
}
void handle_protocol(int x, fd_set *pset, int state[])
{
// we have data packet in socket x. state[x] shows the state of socket x.
// handle the protocol.
int y;
char buf[50];
y = read(x, buf, 50); // read data
buf[y] = 0; // make it a string
if (state[x] == 1) // ex2 : ์ํ๊ฐ 1์ธ ๊ฒฝ์ฐ
handle_state_1(x, pset, buf, state);
else if (state[x] == 2) // ex2 : ์ํ๊ฐ 2์ธ ๊ฒฝ์ฐ
handle_state_2(x, pset, buf, state);
else if (state[x] >= 3 && state[x] <= 7) // ex4 : ์ฑํ
์ก์์ ์ด ๊ฐ๋ฅํ ์ํ (sequence ์๋ฃ)
handle_state_3(x, pset, buf, state);
else if (state[x] == 8) // ex4 : ํ ํด๋ผ์ด์ธํธ๊ฐ ์ฑํ
์ 5๋ฒ ์ด์ ์
๋ ฅํ๋ค๋ฉด,
{
close(x); // ์์ผ์ ๋ซ๊ณ
FD_CLR(x, pset); // pset์์ ํด๋น ์์ผ clear
}
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#define BUFFER_SIZE 50
#define SERV_TCP_PORT 8739
#define SERV_ADDR "165.246.38.151" //"192.168.50.122"
int main()
{
int x, y, i;
struct sockaddr_in serv_addr;
char buf[BUFFER_SIZE];
printf("Hi, I am the client\n");
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = PF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_ADDR);
serv_addr.sin_port = htons(SERV_TCP_PORT);
// open a tcp socket
if ((x = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket creation error\n");
exit(1);
}
printf("socket opened successfully. socket num is %d\n", x);
// connect to the server
if (connect(x, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("can't connect to the server\n");
exit(1);
}
// now start ping-pong-pang-pung protocol
printf("client => serv : (Enter ping) ");
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1); // send "ping"
y = read(x, buf, 50); // read "pong"
buf[y] = '\0';
printf("serv => client : %s\n", buf);
if (strcmp(buf, "pong") != 0)
{
fprintf(stderr, "Error occurred by the protocol.\n");
close(x);
exit(EXIT_FAILURE);
}
printf("client => serv : (Enter pang) ");
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1); // send "pang"
y = read(x, buf, BUFFER_SIZE - 1); // read "pung"
buf[y] = '\0';
printf("serv => client : %s\n", buf);
if (strcmp(buf, "pung. Process completed. Start chatting.") != 0)
{
fprintf(stderr, "Error occurred by the protocol.\n");
close(x);
exit(EXIT_FAILURE);
}
int ch = fork();
if (ch == 0)
{
printf("(Chat)\n");
for (i = 0; i < 5; i++)
{
// printf("client => serv : (Chat) ");
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1);
// write(x, buf, BUFFER_SIZE - 1);
}
close(x);
exit(0);
}
else
{
for (i = 0; i < 5; i++)
{
y = read(x, buf, BUFFER_SIZE - 1);
if (y > 0)
{
buf[y] = '\0';
printf("%s", buf);
// printf("server => client: %s\n", buf);
}
}
}
close(x); // disconect the communication
}
cli[]
array which is an array of client{} structure to store name and age of each client. cli[x]
will remember the client information whose socket number is x
. struct client{
char name[20]; // this client's name
char age[5]; // this client's age as a string
};
......
struct client cli[50]; // max 50 clients
cli aaa=> serv: ping
serv => cli aaa: pong
cli aaa=> serv: pang
serv => cli aaa: pung. name?
cli aaa=> serv: aaa
serv => cli aaa: age?
cli aaa => serv: 19
cli bbb=> serv: ping
serv => cli bbb: pong
cli bbb=> serv: pang
serv => cli bbb: pung. name?
cli bbb=> serv: bbb
serv => cli aaa: age?
cli aaa => serv: 22
cli ccc=> serv: ping
serv => cli ccc: pong
cli ccc=> serv: pang
serv => cli ccc: pung. name?
cli ccc=> serv: ccc
serv => cli aaa: age?
cli aaa => serv: 21
serv => cli aaa: start chatting
serv => cli bbb: start chatting
serv => cli bbb: start chatting
cli aaa => serv: "hello there"
serv=> cli bbb: "aaa 19 to bbb 22: hello there"
serv=> cli ccc: "aaa 19 to ccc 21: hello there"
cli bbb=> serv: "hi"
serv => cli aaa: "bbb 22 to aaa 19: hi"
serv => cli ccc: "bbb 22 to ccc 21: hi"
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#define SERV_TCP_PORT 8739
#define SERV_ADDR "165.246.38.151" //"192.168.50.122"
struct client // ex 5 : ๊ตฌ์กฐ์ฒด ์ ์ธ
{
char name[20]; // ex 5 : ํด๋ผ์ด์ธํธ ์ด๋ฆ
char age[5]; // ex 5 : ํด๋ผ์ด์ธํธ ๋์ด
};
void handle_protocol(int x, fd_set *pset, int state[], struct client cli[]);
void handle_state_1(int x, fd_set *pset, char *buf, int state[]);
void handle_state_2(int x, fd_set *pset, char *buf, int state[]);
void handle_state_3(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
void handle_state_4(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
void handle_state_5(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
int main()
{
int s1, s2, i, x, y;
struct sockaddr_in serv_addr, cli_addr;
char buf[50];
socklen_t xx;
printf("Hi, I am the server\n");
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = PF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_ADDR);
serv_addr.sin_port = htons(SERV_TCP_PORT);
// open a tcp socket
if ((s1 = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket creation error\n");
exit(1);
}
printf("socket opened successfully. socket num is %d\n", s1);
// bind ip
x = bind(s1, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (x < 0)
{
printf("binding failed\n");
exit(1);
}
printf("binding passed\n");
listen(s1, 5);
xx = sizeof(cli_addr);
// now start ping-pong-pang-pung
// pset remembers all sockets to monitor
// rset is the copy of pset passed to select
int maxfd = 50; // just monitor max 50 sockets
int state[maxfd]; // ex2 : ๊ฐ ์์ผ๋ณ ์ํ๋ฅผ ์ ์ฅํ๋ ๋ฐฐ์ด ์ ์ธ
struct client cli[50]; // ex5 : ๊ตฌ์กฐ์ฒด ์์ฑ
fd_set rset, pset;
FD_ZERO(&rset); // init rset
FD_ZERO(&pset); // init pset
// step 1. monitor conn req packet
FD_SET(s1, &pset);
// and loop on select
for (i = 0; i < 20; i++)
{ // should be infinite loop in real life
rset = pset; // step 2
select(maxfd, &rset, NULL, NULL, NULL); // step 3
// now we have some packets
for (x = 0; x < maxfd; x++)
{ // check which socket has a packet
if (FD_ISSET(x, &rset))
{ // socket x has a packet
// s1 is a special socket for which we have to do "accept"
// otherwise do ping-pong-pang-pung
if (x == s1)
{ // new client has arrived
// create a socket for this client
s2 = accept(s1, (struct sockaddr *)&cli_addr, &xx);
state[s2] = 1; // ex2 : ํด๋น ์์ผ์ ์ํ๋ฅผ 1๋ก ์ด๊ธฐํ
printf("new cli at socket %d\n", s2);
FD_SET(s2, &pset); // and include this socket in pset
}
else
{ // data packet. do ping-pong-pang-pung protocol
handle_protocol(x, &pset, state, cli);
}
}
}
}
}
void handle_state_1(int x, fd_set *pset, char *buf, int state[])
{
// socket x is in state 1. Expecting "ping" in buf. if we have ping, send "pong" and
// just update state[x]=2; otherwise send error message and disconnect the connection
if (strcmp(buf, "ping") == 0)
{ // if it is a ping
printf("client at socket %d => serv: ping\n", x);
write(x, "pong", 4); // send pong
printf("serv => client at socket %d: pong\n", x);
}
else
{
printf("client at socket %d => serv: other message\n", x);
write(x, "Error! You should enter \"ping\". Try again!", 44); // send pong
printf("serv => client at socket %d: Error! You should enter \"ping\". Try again!\n", x);
close(x); // ex 2-1 : and stop the protocol
FD_CLR(x, pset); // ex 2-1 : no more monitoring on this socket
}
state[x] = 2; // ex 2 : ์ํ ๊ฐ์ 2๋ก ์ค์
}
void handle_state_2(int x, fd_set *pset, char *buf, int state[])
{
// socket x is in state 2. we are expecting "pang" in buf. If we have "pang", send "pung"
// and close the connection. If we didnโt receive โpangโ, send โprotocol errorโ to the
// client and disconnect.
if (strcmp(buf, "pang") == 0)
{ // it it is a pang
printf("client at socket %d => serv: pang\n", x);
write(x, "pung. name?", 11); // send pung
printf("serv => client at socket %d: pung. name?\n", x);
}
else
{
printf("client at socket %d => serv: %s\n", x, buf);
write(x, "Error! You should enter \"pang\". Try again!", 44); // send pong
printf("serv => client at socket %d: Error! You should enter \"pang\". Try again!\n", x);
close(x); // and stop the protocol
FD_CLR(x, pset); // no more monitoring on this socket
}
state[x] = 3; // ex 3 : ์ํ ๊ฐ์ 3์ผ๋ก ์ค์
}
void handle_state_3(int x, fd_set *pset, char *buf, int state[], struct client cli[])
{
strcpy(cli[x].name, buf); // ex5 : buf(์ด๋ฆ)๋ฅผ ํด๋น ์์ผ์ ์ด๋ฆ ํญ๋ชฉ์ผ๋ก ๋ณต์ฌ
write(x, "age?", 4); // ex5 : age ์์ฒญ ๋ฉ์์ง ์ ์ก
state[x] = 4; // ex5 : ์ํ ๊ฐ์ 4์ผ๋ก ์ค์
}
void handle_state_4(int x, fd_set *pset, char *buf, int state[], struct client cli[])
{
strcpy(cli[x].age, buf); // ex5 : buf(๋์ด)๋ฅผ ํด๋น ์์ผ์ ๋์ด ํญ๋ชฉ์ผ๋ก ๋ณต์ฌ
write(x, "Start Chatting!", 15); // ex5 : chatting ์์ ๋ฉ์์ง ์ ์ก
state[x] = 5; // ex5 : ์ํ ๊ฐ์ 5์ผ๋ก ์ค์
}
void handle_state_5(int x, fd_set *pset, char *buf, int state[], struct client cli[]) // ์ฑํ
์ก์์ ์ด ๊ฐ๋ฅํ ์ํ
{
int i;
char msg[100];
sprintf(msg, "msg from cli %d : %s\n", x, buf); // ๋ฉ์ธ์ง์ ์ก์ ์ ๊ธฐ์ฌ (์์ผ๋ฒํธ ์ด์ฉ)
for (i = 0; i < 50; i++) // ์ต๋ 50๊ฐ ์์ผ๊น์ง monitor
{
if (state[i] >= 3 && i != x) // ์์ผ์ ์ํ๊ฐ 3์ด์์ด๋ฉด์ ์์ ์ด ์๋ ๋
{
write(i, msg, strlen(msg)); // ๋ฉ์ธ์ง ์ ์ก
}
}
state[x]++; // ์ํ + 1
}
void handle_protocol(int x, fd_set *pset, int state[], struct client cli[])
{
// we have data packet in socket x. state[x] shows the state of socket x.
// handle the protocol.
int y;
char buf[50];
y = read(x, buf, 50); // read data
buf[y] = 0; // make it a string
if (state[x] == 1) // ex2 : ์ํ๊ฐ 1์ธ ๊ฒฝ์ฐ
handle_state_1(x, pset, buf, state); // ping ๋์ฐฉ, pong ์ ์ก ์ํ
else if (state[x] == 2) // ex2 : ์ํ๊ฐ 2์ธ ๊ฒฝ์ฐ
handle_state_2(x, pset, buf, state); // pang ๋์ฐฉ, pung ์ ์ก ์ํ
else if (state[x] == 3) // ex5 : ์ํ๊ฐ 3์ธ ๊ฒฝ์ฐ
handle_state_3(x, pset, buf, state, cli); // ex5 : name ๋์ฐฉ, age ์์ฒญ ์ํ
else if (state[x] == 4) // ex5 : ์ํ๊ฐ 3์ธ ๊ฒฝ์ฐ
handle_state_4(x, pset, buf, state, cli); // ex5 : name ๋์ฐฉ, age ์์ฒญ ์ํ
else if (state[x] >= 5 && state[x] <= 9) // ex4 : ์ฑํ
์ก์์ ์ด ๊ฐ๋ฅํ ์ํ (sequence ์๋ฃ)
handle_state_5(x, pset, buf, state, cli);
else if (state[x] == 10) // ex4 : ํ ํด๋ผ์ด์ธํธ๊ฐ ์ฑํ
์ 5๋ฒ ์ด์ ์
๋ ฅํ๋ค๋ฉด,
{
close(x); // ์์ผ์ ๋ซ๊ณ
FD_CLR(x, pset); // pset์์ ํด๋น ์์ผ clear
}
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#define BUFFER_SIZE 50
#define SERV_TCP_PORT 8739
#define SERV_ADDR "165.246.38.151" //"192.168.50.122"
int main()
{
int x, y, i;
struct sockaddr_in serv_addr;
char buf[BUFFER_SIZE];
printf("Hi, I am the client\n");
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = PF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_ADDR);
serv_addr.sin_port = htons(SERV_TCP_PORT);
// open a tcp socket
if ((x = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket creation error\n");
exit(1);
}
printf("socket opened successfully. socket num is %d\n", x);
// connect to the server
if (connect(x, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("can't connect to the server\n");
exit(1);
}
// now start ping-pong-pang-pung protocol
printf("client => serv : (Enter ping) ");
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1); // send "ping"
y = read(x, buf, 50); // read "pong"
buf[y] = '\0';
printf("serv => client : %s\n", buf);
if (strcmp(buf, "pong") != 0)
{
fprintf(stderr, "Error occurred by the protocol.\n");
close(x);
exit(EXIT_FAILURE);
}
printf("client => serv : (Enter pang) ");
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1); // send "pang"
y = read(x, buf, BUFFER_SIZE - 1); // read "pung. name?"
buf[y] = '\0';
printf("serv => client : %s\n", buf); // ex5 : print server message
if (strcmp(buf, "pung. name?") != 0)
{
fprintf(stderr, "Error occurred by the protocol.\n");
close(x);
exit(EXIT_FAILURE);
}
printf("client => serv : ");
fgets(buf, BUFFER_SIZE - 1, stdin); // ex5 : enter name
write(x, buf, strlen(buf) - 1); // ex5 : send name
y = read(x, buf, BUFFER_SIZE - 1); // ex5 : read "age?"
buf[y] = '\0';
printf("serv => client : %s\n", buf); // ex5 : print server message ("age?")
printf("client => serv : ");
fgets(buf, BUFFER_SIZE - 1, stdin); // ex5 : enter age
write(x, buf, strlen(buf) - 1); // ex5 : send age
y = read(x, buf, BUFFER_SIZE - 1); // ex5 : read "Start chatting"
buf[y] = '\0';
printf("serv => client : %s\n", buf); // ex5 : print server message ("Start chatting")
int ch = fork(); // ex4 : ํ๋ก์ธ์ค ๋ณต์
// ex4 : child๋ ์ก์ ๋ด๋น, parents๋ ์์ ๋ด๋น
if (ch == 0)
{
printf("(Chat)\n");
for (i = 0; i < 5; i++)
{
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1);
}
close(x);
exit(0);
}
else
{
for (i = 0; i < 5; i++)
{
y = read(x, buf, BUFFER_SIZE - 1);
if (y > 0)
{
buf[y] = '\0';
printf("%s", buf);
}
}
}
close(x); // disconect the communication
}
client{}
strucure to remember the socket number of the chatting partner. The server should ask which partner the clients wants to talk with and remember the partnerโs socket number in the client{}
structure. Assume if โcli Aโ points to โcli Bโ as a partner, โcli Bโ also points to โcli Aโ as a partner. struct client{
char name[20]; // this client's name
char age[5]; // this client's age as a string
int partner; // the socket number of the chatting partner of this client
};
cli aaa=> serv: ping
serv => cli aaa: pong
cli aaa=> serv: pang
serv => cli aaa: name?
cli aaa=> serv: aaa
cli bbb=> serv: ping
serv => cli bbb: pong
cli bbb=> serv: pang
serv => cli bbb: name?
cli bbb=> serv: bbb
cli ccc=> serv: ping
serv => cli ccc: pong
cli ccc=> serv: pang
serv => cli ccc: name?
cli ccc=> serv: ccc
cli ddd=> serv: ping
serv => cli ddd: pong
cli ddd=> serv: pang
serv => cli ddd: name?
cli ddd=> serv: ddd
serv=>cli aaa: chat partner?
cli aaa=>serv: bbb
serv=>cli bbb: chat partner?
cli bbb=>serv: aaa
serv=>cli ccc: chat partner?
cli ccc=>serv: ddd
serv=>cli ddd: chat partner?
cli ddd=>serv: ccc
serv => cli aaa: start chatting
serv => cli bbb: start chatting
serv => cli ccc: start chatting
serv => cli ddd: start chatting
cli aaa => serv: hello there
serv=> cli bbb: aaa to bbb: hello there
cli bbb=> serv: hi
serv => cli aaa: bbb to aaa: hi
cli ccc => serv: hear me
serv=> cli ddd: ccc to ddd: hear me
cli ddd=> serv: hi there
serv => cli ccc: ddd to ccc: hi there
์ ์ฌ์ง์์ ์ผ์ชฝ ํฐ๋ฏธ๋์ server์ด๊ณ , ์ค๋ฅธ์ชฝ์ 3๊ฐ์ ํฐ๋ฏธ๋์ client๋ฅผ ๋ด๋นํ์๋ค. ํธ์๋ฅผ ์ํด, ์ค๋ฅธ์ชฝ์ client๋ค์ ์์์๋ถํฐ ๊ฐ๊ฐ first, second, third๋ผ๊ณ ํ์.
second์ third๋ ์๋ก๋ฅผ chatting partner๋ก ์ง์ ํ์๋ค. chatting partner๋ก ๋งค์นญ๋ second์ third๋ ๋ํ๊ฐ ๊ฐ๋ฅํ์์ง๋ง, chatting partner๋ฅผ ๋งค์นญํ์ง ๋ชปํจ first์๊ฒ๋ ๋ฉ์ธ์ง๊ฐ ์ค์ง ์์๋ค.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#define SERV_TCP_PORT 8739
#define SERV_ADDR "165.246.38.151" //"192.168.50.122"
struct client // ex 5 : ๊ตฌ์กฐ์ฒด ์ ์ธ
{
char name[20]; // ex 5 : ํด๋ผ์ด์ธํธ ์ด๋ฆ
char age[5]; // ex 5 : ํด๋ผ์ด์ธํธ ๋์ด
int partner; // ex 6 : the socket number of the chatting partner of this client
};
void handle_protocol(int x, fd_set *pset, int state[], struct client cli[]);
void handle_state_1(int x, fd_set *pset, char *buf, int state[]);
void handle_state_2(int x, fd_set *pset, char *buf, int state[]);
void handle_state_3(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
void handle_state_4(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
void handle_state_5(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
int main()
{
int s1, s2, i, x, y;
struct sockaddr_in serv_addr, cli_addr;
char buf[50];
socklen_t xx;
printf("Hi, I am the server\n");
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = PF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_ADDR);
serv_addr.sin_port = htons(SERV_TCP_PORT);
// open a tcp socket
if ((s1 = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket creation error\n");
exit(1);
}
printf("socket opened successfully. socket num is %d\n", s1);
// bind ip
x = bind(s1, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (x < 0)
{
printf("binding failed\n");
exit(1);
}
printf("binding passed\n");
listen(s1, 5);
xx = sizeof(cli_addr);
// now start ping-pong-pang-pung
// pset remembers all sockets to monitor
// rset is the copy of pset passed to select
int maxfd = 50; // just monitor max 50 sockets
int state[maxfd]; // ex2 : ๊ฐ ์์ผ๋ณ ์ํ๋ฅผ ์ ์ฅํ๋ ๋ฐฐ์ด ์ ์ธ
struct client cli[50]; // ex5 : ๊ตฌ์กฐ์ฒด ์์ฑ
fd_set rset, pset;
FD_ZERO(&rset); // init rset
FD_ZERO(&pset); // init pset
// step 1. monitor conn req packet
FD_SET(s1, &pset);
// and loop on select
for (i = 0; i < 40; i++) // ex6 : select ๋ฃจํ ํ์๋ฅผ 20์์ 40์ผ๋ก ๋ณ๊ฒฝ
{ // should be infinite loop in real life
rset = pset; // step 2
select(maxfd, &rset, NULL, NULL, NULL); // step 3
// now we have some packets
for (x = 0; x < maxfd; x++)
{ // check which socket has a packet
if (FD_ISSET(x, &rset))
{ // socket x has a packet
// s1 is a special socket for which we have to do "accept"
// otherwise do ping-pong-pang-pung
if (x == s1)
{ // new client has arrived
// create a socket for this client
s2 = accept(s1, (struct sockaddr *)&cli_addr, &xx);
state[s2] = 1; // ex2 : ํด๋น ์์ผ์ ์ํ๋ฅผ 1๋ก ์ด๊ธฐํ
printf("new cli at socket %d\n", s2);
FD_SET(s2, &pset); // and include this socket in pset
}
else
{ // data packet. do ping-pong-pang-pung protocol
handle_protocol(x, &pset, state, cli);
}
}
}
}
}
void handle_state_1(int x, fd_set *pset, char *buf, int state[])
{
// socket x is in state 1. Expecting "ping" in buf. if we have ping, send "pong" and
// just update state[x]=2; otherwise send error message and disconnect the connection
if (strcmp(buf, "ping") == 0)
{ // if it is a ping
printf("client at socket %d => serv: ping\n", x);
write(x, "pong", 4); // send pong
printf("serv => client at socket %d: pong\n", x);
}
else
{
printf("client at socket %d => serv: other message\n", x);
write(x, "Error! You should enter \"ping\". Try again!", 44); // send pong
printf("serv => client at socket %d: Error! You should enter \"ping\". Try again!\n", x);
close(x); // ex 2-1 : and stop the protocol
FD_CLR(x, pset); // ex 2-1 : no more monitoring on this socket
}
state[x] = 2; // ex 2 : ์ํ ๊ฐ์ 2๋ก ์ค์
}
void handle_state_2(int x, fd_set *pset, char *buf, int state[])
{
// socket x is in state 2. we are expecting "pang" in buf. If we have "pang", send "pung"
// and close the connection. If we didnโt receive โpangโ, send โprotocol errorโ to the
// client and disconnect.
if (strcmp(buf, "pang") == 0)
{ // it it is a pang
printf("client at socket %d => serv: pang\n", x);
write(x, "pung. name?", 11); // send pung
printf("serv => client at socket %d: pung. name?\n", x);
}
else
{
printf("client at socket %d => serv: %s\n", x, buf);
write(x, "Error! You should enter \"pang\". Try again!", 44); // send pong
printf("serv => client at socket %d: Error! You should enter \"pang\". Try again!\n", x);
close(x); // and stop the protocol
FD_CLR(x, pset); // no more monitoring on this socket
}
state[x] = 3; // ex 3 : ์ํ ๊ฐ์ 3์ผ๋ก ์ค์
}
void handle_state_3(int x, fd_set *pset, char *buf, int state[], struct client cli[])
{
strcpy(cli[x].name, buf); // ex5 : buf(์ด๋ฆ)๋ฅผ ํด๋น ์์ผ์ ์ด๋ฆ ํญ๋ชฉ์ผ๋ก ๋ณต์ฌ
write(x, "Chat partner?", 13); // ex6 : chat partner ์์ฒญ ๋ฉ์์ง ์ ์ก
state[x] = 4; // ex5 : ์ํ ๊ฐ์ 4์ผ๋ก ์ค์
}
void handle_state_4(int x, fd_set *pset, char *buf, int state[], struct client cli[])
{
int i;
for (i = 0; i < 50; i++)
{
if (strcmp(cli[i].name, buf) == 0) // ex6 : ์
๋ ฅ๋ฐ์ chat partner(buf)์ ๋์ผํ client name์ด ์์ผ๋ฉด,
cli[x].partner = i; // ex6 : ํด๋น ์์ผ ๋ฒํธ๋ฅผ partner ๋ณ์์ ์ ์ฅ
}
write(x, "Start Chatting!", 15); // ex5 : chatting ์์ ๋ฉ์์ง ์ ์ก
state[x] = 5; // ex5 : ์ํ ๊ฐ์ 5์ผ๋ก ์ค์
}
void handle_state_5(int x, fd_set *pset, char *buf, int state[], struct client cli[]) // ์ฑํ
์ก์์ ์ด ๊ฐ๋ฅํ ์ํ
{
int i;
char msg[100];
sprintf(msg, "msg from cli %d : %s\n", x, buf); // ex6 : ๋ฉ์ธ์ง์ ์ก์ ์(ํ์ฌ cli)์ ์์ ์(partner) ๊ธฐ์ฌ (์์ผ๋ฒํธ ์ด์ฉ)
write(cli[x].partner, msg, strlen(msg)); // ex6 : partner์๊ฒ ๋ฉ์ธ์ง ์ ์ก
state[x]++; // ์ํ + 1
}
void handle_protocol(int x, fd_set *pset, int state[], struct client cli[])
{
// we have data packet in socket x. state[x] shows the state of socket x.
// handle the protocol.
int y;
char buf[50];
y = read(x, buf, 50); // read data
buf[y] = 0; // make it a string
if (state[x] == 1) // ex2 : ์ํ๊ฐ 1์ธ ๊ฒฝ์ฐ
handle_state_1(x, pset, buf, state); // ping ๋์ฐฉ, pong ์ ์ก ์ํ
else if (state[x] == 2) // ex2 : ์ํ๊ฐ 2์ธ ๊ฒฝ์ฐ
handle_state_2(x, pset, buf, state); // pang ๋์ฐฉ, pung ์ ์ก ์ํ
else if (state[x] == 3) // ex5 : ์ํ๊ฐ 3์ธ ๊ฒฝ์ฐ
handle_state_3(x, pset, buf, state, cli); // ex5 : name ๋์ฐฉ, age ์์ฒญ ์ํ
else if (state[x] == 4) // ex5 : ์ํ๊ฐ 3์ธ ๊ฒฝ์ฐ
handle_state_4(x, pset, buf, state, cli); // ex5 : name ๋์ฐฉ, age ์์ฒญ ์ํ
else if (state[x] >= 5 && state[x] <= 9) // ex4 : ์ฑํ
์ก์์ ์ด ๊ฐ๋ฅํ ์ํ (sequence ์๋ฃ)
handle_state_5(x, pset, buf, state, cli);
else if (state[x] == 10) // ex4 : ํ ํด๋ผ์ด์ธํธ๊ฐ ์ฑํ
์ 5๋ฒ ์ด์ ์
๋ ฅํ๋ค๋ฉด,
{
close(x); // ์์ผ์ ๋ซ๊ณ
FD_CLR(x, pset); // pset์์ ํด๋น ์์ผ clear
}
}
cliping.c
๋ 6๋ฒ์ ์ฝ๋๋ฅผ ๊ทธ๋๋ก ์ด์ฉํ์๋ค.
cli[x].name
, where x
is the socket number of this client.3
.cli[x].partner
.cli[x].partner
.All clientโs initial state is 1
.
cli eee => serv: hello
serv => cli eee: name?
cli eee=> serv: eee
serv => cli eee: ready?
cli eee => serv : yes
serv => cli eee: client list (aaa bbb ccc โฆ..)
cli eee=> serv : bbb
serv => cli eee: go
................
cli bbb => serv : yes
serv => cli bbb : client list (aaa bbb ccc eee ...)
cli bbb => serv : eee
serv => cli bbb : go
cli eee => serv : hi how are you
serv => cli bbb : hi how are you
cli bbb => serv : hi there
serv => cli eee : hi there
..............
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#define SERV_TCP_PORT 8739
#define SERV_ADDR "165.246.38.151" //"192.168.50.122"
struct client // ex 5 : ๊ตฌ์กฐ์ฒด ์ ์ธ
{
char name[20]; // ex 5 : ํด๋ผ์ด์ธํธ ์ด๋ฆ
char age[5]; // ex 5 : ํด๋ผ์ด์ธํธ ๋์ด
int partner; // ex 6 : the socket number of the chatting partner of this client
int state;
};
void handle_protocol(int x, fd_set *pset, int state[], struct client cli[]);
void handle_state_1(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
void handle_state_2(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
void handle_state_3(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
void handle_state_4(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
void handle_state_5(int x, fd_set *pset, char *buf, int state[], struct client cli[]);
int main()
{
int s1, s2, i, x, y;
struct sockaddr_in serv_addr, cli_addr;
char buf[50];
socklen_t xx;
printf("Hi, I am the server\n");
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = PF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_ADDR);
serv_addr.sin_port = htons(SERV_TCP_PORT);
// open a tcp socket
if ((s1 = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket creation error\n");
exit(1);
}
printf("socket opened successfully. socket num is %d\n", s1);
// bind ip
x = bind(s1, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (x < 0)
{
printf("binding failed\n");
exit(1);
}
printf("binding passed\n");
listen(s1, 5);
xx = sizeof(cli_addr);
// pset remembers all sockets to monitor
// rset is the copy of pset passed to select
int maxfd = 50; // just monitor max 50 sockets
int state[maxfd]; // ex2 : ๊ฐ ์์ผ๋ณ ์ํ๋ฅผ ์ ์ฅํ๋ ๋ฐฐ์ด ์ ์ธ
struct client cli[50]; // ex5 : ๊ตฌ์กฐ์ฒด ์์ฑ
for (i = 0; i < 50; i++)
cli[i].state = 0; // ex7 : ๋ชจ๋ ํ๋ณด ์์ผ๋ค์ ์ด๊ธฐ state๋ 0์ผ๋ก ์ค์
fd_set rset, pset;
FD_ZERO(&rset); // init rset
FD_ZERO(&pset); // init pset
// step 1. monitor conn req packet
FD_SET(s1, &pset);
// and loop on select
for (i = 0; i < 40; i++) // ex6 : select ๋ฃจํ ํ์๋ฅผ 20์์ 40์ผ๋ก ๋ณ๊ฒฝ
{ // should be infinite loop in real life
rset = pset; // step 2
select(maxfd, &rset, NULL, NULL, NULL); // step 3
// now we have some packets
for (x = 0; x < maxfd; x++)
{ // check which socket has a packet
if (FD_ISSET(x, &rset))
{ // socket x has a packet
// s1 is a special socket for which we have to do "accept"
if (x == s1)
{ // new client has arrived
// create a socket for this client
s2 = accept(s1, (struct sockaddr *)&cli_addr, &xx);
cli[s2].state = 1; // ex7 : ์๋ก ์์ฑ๋ ํด๋ผ์ด์ธํธ ์์ผ์ ์ํ๋ฅผ 1๋ก ์ค์
printf("new cli at socket %d\n", s2);
FD_SET(s2, &pset); // and include this socket in pset
}
else
{
handle_protocol(x, &pset, state, cli);
}
}
}
}
}
void handle_state_1(int x, fd_set *pset, char *buf, int state[], struct client cli[])
{
if (strcmp(buf, "hello") == 0) // ex7 : "hello"๋ฅผ ๋ฐ์ผ๋ฉด
{
printf("client at socket %d => serv: hello\n", x);
write(x, "name?", 5); // ex7 : send "name?"
printf("serv => client at socket %d: name?\n", x);
}
else
{
printf("client at socket %d => serv: other message\n", x);
write(x, "Error! You should enter \"hello\". Try again!", 44); // send Error message
printf("serv => client at socket %d: Error! You should enter \"hello\". Try again!\n", x);
close(x); // ex 2-1 : and stop the protocol
FD_CLR(x, pset); // ex 2-1 : no more monitoring on this socket
}
cli[x].state = 2; // ex 2 : ์ํ ๊ฐ์ 2๋ก ์ค์
}
void handle_state_2(int x, fd_set *pset, char *buf, int state[], struct client cli[])
{
strcpy(cli[x].name, buf); // ex7 : buf(์ด๋ฆ)๋ฅผ ํด๋น ์์ผ์ ๊ตฌ์กฐ์ฒด์ ์ด๋ฆ ํญ๋ชฉ์ผ๋ก ๋ณต์ฌ
printf("client at socket %d => serv: %s\n", x, cli[x].name); // ๋๋ต ์ถ๋ ฅ
write(x, "Ready?", 6); // ex7 : "Ready?" ๋ฉ์์ง ์ ์ก
printf("serv => client at socket %d: Ready?\n", x);
cli[x].state += 1; // ex3 : ์ํ ๊ฐ์ 3์ผ๋ก ์ค์
}
void handle_state_3(int x, fd_set *pset, char *buf, int state[], struct client cli[])
{
int i;
printf("client at socket %d => serv: %s\n", x, buf); // ๋๋ต ์ถ๋ ฅ
if (strcmp(buf, "yes") == 0) // ex7 : "Ready?"์ ๋ํ ๋๋ต์ผ๋ก "yes"๋ฅผ ๋ฐ์ผ๋ฉด
{
// ex7 : client list๋ฅผ ๋ณด๋
strcpy(buf, "client list (");
for (i = 0; i < 50; i++)
{
if (x != i && cli[i].state > 2)
{
strcat(buf, cli[i].name);
strcat(buf, ", ");
}
}
if (buf[strlen(buf) - 2] == ',')
{
buf[strlen(buf) - 2] = '\0';
}
strcat(buf, ")");
write(x, buf, strlen(buf));
printf("serv => client at socket %d: %s\n", x, buf);
cli[x].state += 1;
}
else
{
printf("client at socket %d => serv: other message\n", x);
write(x, "You are not ready yet!", 22); // ex7 : send Error message
printf("serv => client at socket %d: You are not ready yet!\n", x);
close(x); // ex 2-1 : and stop the protocol
FD_CLR(x, pset); // ex 2-1 : no more monitoring on this socket
}
}
void handle_state_4(int x, fd_set *pset, char *buf, int state[], struct client cli[])
{
int i;
printf("client at socket %d => serv: %s\n", x, buf);
for (i = 0; i < 50; i++)
{
if (x != i && cli[i].state > 2 && strcmp(cli[i].name, buf) == 0) // ex6 : ์
๋ ฅ๋ฐ์ chat partner(buf)์ ๋์ผํ client name์ด ์์ผ๋ฉด,
{
cli[x].partner = i; // ex6 : ํด๋น ์์ผ ๋ฒํธ๋ฅผ partner ๋ณ์์ ์ ์ฅ
write(x, "Go!", 3); // ex7 : chatting ์์ ๋ฉ์์ง ์ ์ก
cli[x].state += 1; // ex5 : ์ํ ๊ฐ์ 5์ผ๋ก ์ค์
break;
}
}
}
void handle_state_5(int x, fd_set *pset, char *buf, int state[], struct client cli[]) // ์ฑํ
์ก์์ ์ด ๊ฐ๋ฅํ ์ํ
{
char msg[50];
int len = sprintf(msg, "%s => %s : %s", cli[x].name, cli[cli[x].partner].name, buf);
write(cli[x].partner, msg, len); // ex6 : partner์๊ฒ ๋ฉ์ธ์ง ์ ์ก
printf("%s\n", msg);
cli[x].state++; // ์ํ + 1
}
void handle_protocol(int x, fd_set *pset, int state[], struct client cli[])
{
// we have data packet in socket x.
// cli[x].state shows the state of socket x.
// handle the protocol.
int y;
char buf[50];
y = read(x, buf, 50); // read data
buf[y] = 0; // make it a string
if (cli[x].state == 1) // ex2 : ์ํ๊ฐ 1์ธ ๊ฒฝ์ฐ
handle_state_1(x, pset, buf, state, cli); // hello ๋์ฐฉ, pong ์ ์ก ์ํ
else if (cli[x].state == 2) // ex2 : ์ํ๊ฐ 2์ธ ๊ฒฝ์ฐ
handle_state_2(x, pset, buf, state, cli); // pang ๋์ฐฉ, pung ์ ์ก ์ํ
else if (cli[x].state == 3) // ex5 : ์ํ๊ฐ 3์ธ ๊ฒฝ์ฐ
handle_state_3(x, pset, buf, state, cli); // ex5 : name ๋์ฐฉ, age ์์ฒญ ์ํ
else if (cli[x].state == 4) // ex5 : ์ํ๊ฐ 3์ธ ๊ฒฝ์ฐ
handle_state_4(x, pset, buf, state, cli); // ex5 : name ๋์ฐฉ, age ์์ฒญ ์ํ
else if (cli[x].state >= 5 && cli[x].state <= 9) // ex4 : ์ฑํ
์ก์์ ์ด ๊ฐ๋ฅํ ์ํ (sequence ์๋ฃ)
handle_state_5(x, pset, buf, state, cli);
else if (cli[x].state == 10) // ex4 : ํ ํด๋ผ์ด์ธํธ๊ฐ ์ฑํ
์ 5๋ฒ ์ด์ ์
๋ ฅํ๋ค๋ฉด,
{
close(x); // ์์ผ์ ๋ซ๊ณ
FD_CLR(x, pset); // pset์์ ํด๋น ์์ผ clear
}
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>
#define BUFFER_SIZE 50
#define SERV_TCP_PORT 8739
#define SERV_ADDR "165.246.38.151" //"192.168.50.122"
int main()
{
int x, y, i;
struct sockaddr_in serv_addr;
char buf[BUFFER_SIZE];
printf("Hi, I am the client\n");
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = PF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_ADDR);
serv_addr.sin_port = htons(SERV_TCP_PORT);
// open a tcp socket
if ((x = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket creation error\n");
exit(1);
}
printf("socket opened successfully. socket num is %d\n", x);
// connect to the server
if (connect(x, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("can't connect to the server\n");
exit(1);
}
printf("client => serv : (Enter hello) ");
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1); // send "hello"
y = read(x, buf, 50); // read "name?"
buf[y] = '\0';
printf("serv => client : %s\n", buf);
if (strcmp(buf, "name?") != 0)
{
fprintf(stderr, "Error occurred by the protocol.\n");
close(x);
exit(EXIT_FAILURE);
}
printf("client => serv : (Enter name) ");
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1); // send name
y = read(x, buf, BUFFER_SIZE - 1); // read "Ready?"
buf[y] = '\0';
printf("serv => client : %s\n", buf); // ex5 : print server message
if (strcmp(buf, "Ready?") != 0)
{
fprintf(stderr, "Error occurred by the protocol.\n");
close(x);
exit(EXIT_FAILURE);
}
printf("client => serv : (Enter yes/no) ");
fgets(buf, BUFFER_SIZE - 1, stdin); // ex5 : enter "yes"
write(x, buf, strlen(buf) - 1); // ex5 : send "yes"
y = read(x, buf, BUFFER_SIZE - 1); // ex5 : read "client list"s
buf[y] = '\0';
printf("serv => client : %s\n", buf); // ex5 : print server message ("client list"s)
printf("client => serv : (Enter partner) ");
fgets(buf, BUFFER_SIZE - 1, stdin); // ex5 : enter client lists
write(x, buf, strlen(buf) - 1); // ex5 : send client
y = read(x, buf, BUFFER_SIZE - 1); // ex5 : read "Go!"
buf[y] = '\0';
printf("serv => client : %s\n", buf); // ex5 : print server message ("Go!")
if (strcmp(buf, "Go!") != 0)
{
fprintf(stderr, "Error occurred by the protocol.\n");
close(x);
exit(EXIT_FAILURE);
}
int ch = fork(); // ex4 : ํ๋ก์ธ์ค ๋ณต์
// ex4 : child๋ ์ก์ ๋ด๋น, parents๋ ์์ ๋ด๋น
if (ch == 0)
{
printf("(Chat)\n");
while (1)
{
fgets(buf, BUFFER_SIZE - 1, stdin);
write(x, buf, strlen(buf) - 1);
}
}
else
{
while (1)
{
y = read(x, buf, BUFFER_SIZE - 1);
if (y > 0)
{
buf[y] = '\0';
printf("%s\n", buf);
}
}
}
close(x); // disconect the communication
return 0;
}