Difference between revisions of "Server.c"

From Organic Design wiki
m
(actually this is wrong - should use select())
Line 8: Line 8:
 
#define BUFSIZE 10000 // max message size
 
#define BUFSIZE 10000 // max message size
 
#define MAXCLIENTS 100
 
#define MAXCLIENTS 100
#define MSG "stink ow!"
 
  
 
// - todo: don't exit on connect errors, keep trying every 10s
 
// - todo: don't exit on connect errors, keep trying every 10s
Line 17: Line 16:
 
#include <sys/socket.h>
 
#include <sys/socket.h>
 
#include <netinet/in.h>
 
#include <netinet/in.h>
#include <fcntl.h>
+
#include <fcntl.h> // needed for O_NONBLOCK option on server
 
//#include <arpa/inet.h>
 
//#include <arpa/inet.h>
 
//#include <netdb.h>
 
//#include <netdb.h>
Line 41: Line 40:
 
// get a socket
 
// get a socket
 
int server;
 
int server;
if ((server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+
if ((server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) logAdd("socket() failed!";
perror("socket");
 
exit(1);
 
}
 
  
 
// make it reusable
 
// make it reusable
 
int sockopt_on = 1;
 
int sockopt_on = 1;
if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &sockopt_on, sizeof(int)) < 0) {
+
if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &sockopt_on, sizeof(int)) < 0) logAdd("setsockopt() failed!";
perror("setsockopt");
 
exit(1);
 
}
 
  
 
// bind our socket to the port
 
// bind our socket to the port
if (bind(server, (struct sockaddr *)&my_addr, sa_in_size) < 0) {
+
if (bind(server, (struct sockaddr *)&my_addr, sa_in_size) < 0) logAdd("bind() failed!";
perror("bind");
 
exit(1);
 
}
 
  
 
// start listening for incoming connections
 
// start listening for incoming connections
if (listen(server, BACKLOG) < 0) {
+
if (listen(server, BACKLOG) < 0) logAdd("listen() failed!";
perror("listen");
 
exit(1);
 
}
 
  
 
// make the server non-blocking so accept() returns straight away
 
// make the server non-blocking so accept() returns straight away
Line 80: Line 67:
 
stream = accept(server, (struct sockaddr *)&client_addr, &sa_in_size)
 
stream = accept(server, (struct sockaddr *)&client_addr, &sa_in_size)
 
if (stream == EAGAIN) {
 
if (stream == EAGAIN) {
// No connection requests
+
// No new connection requests - read any available data from streams
 +
for (i = 0; i < nStreams; i++) {
 +
char* buf = streams[i].buf;
 +
int stream = streams[i].fileno;
 +
}
 
}
 
}
else if (stream < 0) {
+
else if (stream == ECONNABORTED) {
perror("accept");
+
logAdd("Stream closed by client");
exit(1);
+
close(stream);
 
}
 
}
 +
else if (stream < 0) logAdd("accept() failed!";
 
else {
 
else {
 
// New stream, create input buffer etc
 
// New stream, create input buffer etc
Line 94: Line 86:
 
}
 
}
  
// loop thru streams and read a packet from any with data to read
 
for (i = 0; i < nStreams; i++) {
 
char* buf = streams[i].buf;
 
int stream = streams[i].fileno;
 
}
 
  
 
// log the connecter
 
// log the connecter
Line 108: Line 95:
 
if (recv(stream, buf, bufsize, 0) == -1) perror("recv");
 
if (recv(stream, buf, bufsize, 0) == -1) perror("recv");
 
else printf("The client says \"%s\"\n", buf);
 
else printf("The client says \"%s\"\n", buf);
 
close(stream); // should close when no more data on this stream (somehow)
 
  
 
}
 
}

Revision as of 04:01, 3 July 2006

// good sock function ref at // http://www.opengroup.org/onlinepubs/009695399/idx/networking.html

// Set up socket and listening loop

  1. define LISTENPORT 2012
  2. define BACKLOG 10
  3. define PAKSIZE 128 // keep packet-size small for non-multithreaded design
  4. define BUFSIZE 10000 // max message size
  5. define MAXCLIENTS 100

// - todo: don't exit on connect errors, keep trying every 10s // Includes for socket (trying to use one source cpp for osx,win32,*ux)

  1. ifdef WINDOWS
  2. include <winsock.h>
  3. else
  4. include <sys/socket.h>
  5. include <netinet/in.h>
  6. include <fcntl.h> // needed for O_NONBLOCK option on server

//#include <arpa/inet.h> //#include <netdb.h> //#include <unistd.h>

  1. endif

int processMessage(char* msg);

// struct type to represent a currently connected stream typedef struct streamstruct { char* buf; int fileno; } streamInfo;

// set up socket struct struct sockaddr_in my_addr, client_addr; int sa_in_size = sizeof(struct sockaddr_in); memset((char *)&my_addr, 0, sa_in_size); // zero the struct my_addr.sin_family = PF_INET; my_addr.sin_port = htons(LISTENPORT); my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

// get a socket int server; if ((server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) logAdd("socket() failed!";

// make it reusable int sockopt_on = 1; if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &sockopt_on, sizeof(int)) < 0) logAdd("setsockopt() failed!";

// bind our socket to the port if (bind(server, (struct sockaddr *)&my_addr, sa_in_size) < 0) logAdd("bind() failed!";

// start listening for incoming connections if (listen(server, BACKLOG) < 0) logAdd("listen() failed!";

// make the server non-blocking so accept() returns straight away // - if no incoming requests, returns EAGAIN or EWOULDBLOCK state // - we need this for non-multithreaded design fcntl(server, O_NONBLOCK);

// array of current client connections streamInfo* streams[MAXCLIENTS];

int i, stream, nStreams = 0; while(1) {

// Wait for any incomming connection // O_NONBLOCK is set so, EAGAIN or EWOULDBLOCK returned if no requests stream = accept(server, (struct sockaddr *)&client_addr, &sa_in_size) if (stream == EAGAIN) { // No new connection requests - read any available data from streams for (i = 0; i < nStreams; i++) { char* buf = streams[i].buf; int stream = streams[i].fileno; } } else if (stream == ECONNABORTED) { logAdd("Stream closed by client"); close(stream); } else if (stream < 0) logAdd("accept() failed!"; else { // New stream, create input buffer etc streamInfo si; si.buf = malloc(BUFSIZE); si.fileno = stream; streams[nStreams++] = &si; }


// log the connecter // - should get info for this stream, incl buf printf("got connection from %s\n", inet_ntoa(client_addr.sin_addr));

// get the reply // - should keep receiving until \r\n\0?, then call serverProcessMessage() if (recv(stream, buf, bufsize, 0) == -1) perror("recv"); else printf("The client says \"%s\"\n", buf);

}

// Parses a message content and responds to client int processMessage(char* msg) { // test if restart cmd first

// send response if (send(stream, MSG, strlen(MSG)+1, 0) == -1) { perror("send"); } else printf("Sent message MSG\n"); }