Back to home

BSD sockets on Mac

So now and then I need to have send some data from one application to another one. Having a simple test server around which you easily debug is very nice to have. Therefore I past this snippet of code which creates a tcp server which working on unix/linux. It's purpose is to be used as a snippet for a test server, not for a fully fledged server.  I'm working on some demo applications for a iPhone class I'll be teaching which involve communication with a server. Stay tuned for more info on this! I'm using the Poco threading classes (which you can remove if you want to)

LEDServer.h

#ifndef LEDSERVERH
#define LEDSERVERH
 
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Poco/Thread.h"
#include <vector>
#include <map>
 
using std::vector;
using std::map;
class LEDClient;
class LEDServer : public Poco::Runnable {
public:
	LEDServer();
	~LEDServer();
	void start();
	void run();
private:
	int server_socket;
	int server_port;
	struct sockaddr_in server_addr;
	Poco::Thread thread;
	map<int, LEDClient*> clients;
};
#endif

LEDServer.cpp

#include "LEDServer.h"
#include "LEDClient.h"
 
LEDServer::LEDServer() 
:server_socket(0)
,server_port(8888)
{
}
 
LEDServer::~LEDServer() {
	thread.join();
}
 
void LEDServer::start() {
	thread.start(*this);
}
 
void LEDServer::run() {
	server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(server_socket == -1) {
		printf("Can't create server socket\n");
	}	
 
	int result = 0;
	int val;
	result = setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
	if(result < 0) {
		printf("Cannot reuse address\n");
		exit(1);
	}
 
	// bind.	
	bzero(&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(8888);
	result = bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
	if(result != 0) {
		printf("Cannot bind...\n");
		exit(1);
	}
 
	// listen
	result = listen(server_socket, 5);
	if(result < 0) {
		printf("Cannot set listen mode to socket\n");
		close(server_socket);
		exit(1);
	}
 
	// some sets
	fd_set socket_readset, test_set;
	FD_ZERO(&socket_readset);
	FD_SET(server_socket, &socket_readset);
 
 
 
	while(true) {
		// get notified by readset.
		test_set = socket_readset;
		result = select(FD_SETSIZE, &test_set, NULL, NULL, NULL);
		if(result < 1) {
			printf("Server error\n");
			exit(1);
		}
 
		for(int i = 0; i < FD_SETSIZE; ++i) {
			if(FD_ISSET(i, &test_set)) {
				if(i == server_socket) {
					// listen for a new connection.
					struct sockaddr_in client_addr = {0};
					int child_socket = 0; 
					int client_addr_len = sizeof(client_addr);
					child_socket = accept(server_socket, (struct sockaddr*)&client_addr, (socklen_t*) &client_addr_len);
 
					if(child_socket == -1) {
						printf("Cannot accept connections\n");
						close(server_socket);
						exit(1);
					}
 
					// store our new client.
					FD_SET(child_socket, &socket_readset);
					LEDClient* lc = new LEDClient(child_socket);
					clients.insert(std::pair<int,LEDClient*>(child_socket, lc));
				}	
				else {
					map<int, LEDClient*>::iterator it = clients.find(i);
					if(it != clients.end()) {
						it->second->readFromSocket();
					}					
				}
			}
		}
	}
 
	// clean up..
	map<int, LEDClient*>::iterator it = clients.begin();
	while(it != clients.end()) {
		delete it->second;
		++it;
	}
}

LEDClient.h

#ifndef LEDCLIENTH
#define LEDCLIENTH
 
 
#include <iostream>
#include <vector>
 
using namespace std;
 
class LEDClient {
public:
	LEDClient(int clientSock);
	void readFromSocket();
	int sock;
	vector<char> buffer;
};
 
#endif

LEDClient.cpp

#include "LEDClient.h"
LEDClient::LEDClient(int clientSock)
	:sock(clientSock)
{
}
 
void LEDClient::readFromSocket() {
	char tmp_buf[512];
	ssize_t bytes_read = read(sock, tmp_buf, 512);
	std::copy(tmp_buf, tmp_buf+bytes_read, std::back_inserter(buffer));
 
	// show what we got so far.
	cout << "Now in buffer (" << buffer.size() << ") = " ;
	for(int i = 0; i < buffer.size(); ++i) {
		cout << buffer[i];
	}
	cout << endl;
 
}