Created
May 1, 2014 17:23
-
-
Save oxnz/855b94ee4a4aae3c8c88 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <sys/select.h> | |
#include <sys/time.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <arpa/inet.h> | |
#define BUFLEN 10U | |
unsigned char buf[BUFLEN]; | |
const unsigned short PORT(8888); | |
#define BACKLOG 16U | |
void errpro(int condition, const char *errmsg) { | |
if (condition) { | |
perror(errmsg); | |
exit(EXIT_FAILURE); | |
} | |
} | |
int clientpro(int fda[], unsigned int idx) { | |
int ret(0); | |
int cnt = recv(fda[idx], buf, BUFLEN-1, 0); | |
errpro(-1 == cnt, "recv"); | |
if (0 == cnt) { // client go off | |
printf("client[%u] goes off\n", idx); | |
} else { | |
ret = cnt; | |
printf("-->[0x%x]\n", buf[0]); | |
switch (buf[0]) { | |
case 0x04: | |
printf("^D\n"); | |
break; | |
case 0x73: | |
printf("getstatus\n"); | |
break; | |
case 0xff: | |
printf("client[%u] logout\n", idx); | |
return 0; | |
break; | |
default: | |
break; | |
} | |
buf[cnt] = '\0'; | |
printf("message from client[%u]:\n%s", idx, buf); | |
while (BUFLEN-1 == cnt) { | |
cnt = recv(fda[idx], buf, BUFLEN-1, 0); | |
ret += cnt; | |
errpro(-1 == cnt, "recv"); | |
buf[cnt] = '\0'; | |
printf("%s", buf); | |
} | |
char msg[] = "Hello, client x\n"; | |
msg[strlen(msg)-2] = idx + '0'; | |
errpro(-1 == send(fda[idx], msg, strlen(msg)+1, 0), "send"); | |
} | |
return ret; | |
} | |
int main(int argc, char *argv[]) { | |
struct sockaddr_in server_addr, client_addr; | |
socklen_t sin_size(sizeof(server_addr)); | |
int sockfd; | |
errpro(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)), "socket"); | |
int opval = 1; | |
errpro(-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opval, | |
sizeof(opval)), "setsockopt"); | |
server_addr.sin_family = AF_INET; | |
server_addr.sin_port = htons(PORT); | |
server_addr.sin_addr.s_addr = INADDR_ANY; | |
memset(server_addr.sin_zero, 0, sizeof(server_addr.sin_zero)); | |
errpro(-1 == bind(sockfd, (struct sockaddr *)&server_addr, | |
sin_size), "bind"); | |
errpro(-1 == listen(sockfd, BACKLOG), "listen"); | |
printf("listen on port: %u\n", PORT); | |
int maxsockfd(sockfd); | |
struct timeval tv; | |
unsigned int conn_cnt(0); | |
int fda[BACKLOG]; // accepted connection fds | |
memset(fda, 0, sizeof(fda)); | |
fd_set fds; | |
while (1) { | |
// init file descriptor set | |
FD_ZERO(&fds); | |
FD_SET(sockfd, &fds); | |
// set timeout | |
tv.tv_sec = 10; | |
tv.tv_usec = 0; | |
// add active connection to fd set | |
for (unsigned int i = 0; i < BACKLOG; ++i) { | |
if (fda[i] != 0) { | |
FD_SET(fda[i], &fds); | |
} | |
} | |
switch (select(maxsockfd+1, &fds, NULL, NULL, &tv)) { | |
case -1: | |
errpro(EXIT_FAILURE, "select"); | |
break; | |
case 0: | |
printf("timeout\n"); | |
continue; | |
break; | |
default: | |
break; | |
} | |
// check every fd in the set | |
for (unsigned int i = 0; i < conn_cnt; ++i) { | |
if (FD_ISSET(fda[i], &fds)) { | |
if (0 == clientpro(fda, i)) { | |
--conn_cnt; | |
close(fda[i]); | |
FD_CLR(fda[i], &fds); | |
fda[i] = 0; | |
} | |
} | |
} | |
// check whether a new connection comes | |
if (FD_ISSET(sockfd, &fds)) { | |
int fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); | |
errpro(-1 == fd, "accept"); | |
// add fd to queue | |
if (conn_cnt < BACKLOG) { | |
fda[conn_cnt++] = fd; | |
printf("new connection client[%u] %s:%u\n", conn_cnt, | |
inet_ntoa(client_addr.sin_addr), | |
ntohs(client_addr.sin_port)); | |
maxsockfd = fd > maxsockfd ? fd : maxsockfd; | |
} else { | |
printf("max connections reached, ignore new connection\n"); | |
char msg[] = "sorry, server is busy, please try later\n"; | |
errpro(-1 == send(fd, msg, strlen(msg)+1, 0), "send"); | |
close(fd); | |
} | |
} | |
printf("client count: %u\n", conn_cnt); | |
} | |
// close active connections | |
for (unsigned int i = 0; i < BACKLOG; ++i) { | |
fda[i] != 0 ? close(fda[i]) : 0; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment