Skip to content

Instantly share code, notes, and snippets.

@oxnz
Created May 1, 2014 17:23
Show Gist options
  • Save oxnz/855b94ee4a4aae3c8c88 to your computer and use it in GitHub Desktop.
Save oxnz/855b94ee4a4aae3c8c88 to your computer and use it in GitHub Desktop.
#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