ysan / immsocket

socket library which can be used immediately (sock_stream) (unix_domain/inet_domain)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

immsocket

socket library which can be used immediately (sock_stream) (unix_domain/inet_domain) a kind of short packet message exchanger.

How to build

Clone and make.

$ git clone https://github.com/ysan/immsocket
$ cd immsocket
$ make

Then shared libraries is created.

$ tree -P *.so
.
├── immsocket
│   └── libimmsocket.so
├── immsocketcommon
│   └── libimmsocketcommon.so
└── immsocketservice
    └── libimmsocketservice.so

Example of use (sample codes)

server code (echo server)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#include "ImmSocketService.h"

using namespace std;
using namespace ImmSocketService;


//
// You inherit CPacketHandler and implement the following three methods.
// - onHandleRequest
// - onHandleReply
// - onHandleNotify
//
//  Attention:
//    If there are multiple thread pools, the above functions are called in parallel.
//    Therefore, reentrant code is mandatory.
//    Also, putting mutex makes sense of thread pool meaningless.
//
class CSvrMessageHandler : public CPacketHandler
{
public:
	explicit CSvrMessageHandler (int threadPoolNum) : CPacketHandler (threadPoolNum) {}
	virtual ~CSvrMessageHandler (void) {}

private:
	void onHandleRequest (CRequestMessage *pRequestMsg) override {
		_UTL_LOG_I ("%s\n", __PRETTY_FUNCTION__);
		switch ((int)pRequestMsg->getCommand()) {
		case 0x01: {
			char *p = (char*)pRequestMsg->getData();
			_UTL_LOG_I ("received ->  [%s]\n", p);

			CReplyMessage *pReplyMsg = new CReplyMessage (pRequestMsg);
			pReplyMsg->sendOK ((uint8_t*)p, (int)strlen(p)); // echo reply
			delete pReplyMsg;
			pReplyMsg = NULL;
			} break;
		default: {
			CReplyMessage *pReplyMsg = new CReplyMessage (pRequestMsg);
			pReplyMsg->sendNG();
			delete pReplyMsg;
			pReplyMsg = NULL;
			} break;
		}
	}

	void onHandleReply (CReplyMessage *pReplyMsg) override {
		_UTL_LOG_I ("%s\n", __PRETTY_FUNCTION__);
	}

	void onHandleNotify (CNotifyMessage *pNotifyMsg) override {
		_UTL_LOG_I ("%s\n", __PRETTY_FUNCTION__);
	}
};

int main (void)
{ 
//TODO
	sigset_t sigset;
	sigemptyset (&sigset);
	sigaddset (&sigset, SIGPIPE);
	sigprocmask (SIG_BLOCK, &sigset, NULL);


	// Specify a class that inherits from CPacketHandler in template.
	// Specify message handle thread pool num = 2
	// CSvrMessageHandler instance is created for each client connection.
	// thread pool is created for each connection.
	CClientHandler<CSvrMessageHandler> *pClientHandler = new CClientHandler<CSvrMessageHandler> (2);

	CServer server (65000, pClientHandler); // specified tcp port 65000
	server.start();


	fgetc (stdin);


	server.syncStop();


	if (pClientHandler) {
		delete pClientHandler;
		pClientHandler = NULL;
	}


	exit (EXIT_SUCCESS);
}

client code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#include "ImmSocketService.h"

 
using namespace std;
using namespace ImmSocketService;


CMessageId::CId g_id;

//
// You inherit CPacketHandler and implement the following three methods.
// - onHandleRequest
// - onHandleReply
// - onHandleNotify
//
//  Attention:
//    If there are multiple thread pools, the above functions are called in parallel.
//    Therefore, reentrant code is mandatory.
//    Also, putting mutex makes sense of thread pool meaningless.
//
class CClMessageHandler : public CPacketHandler
{
public:
	explicit CClMessageHandler (int threadPoolNum) : CPacketHandler (threadPoolNum) {}
	virtual ~CClMessageHandler (void) {}

private:
	void onHandleRequest (CRequestMessage *pRequestMsg) override {
		_UTL_LOG_I ("%s\n", __PRETTY_FUNCTION__);
	}

	void onHandleReply (CReplyMessage *pReplyMsg) override {
		_UTL_LOG_I ("%s\n", __PRETTY_FUNCTION__);
		CMessageId::CId id = *pReplyMsg->getId();
		if (id == g_id) { // id match
			_UTL_LOG_I ("%s (async)\n", pReplyMsg->isReplyResultOK() ? "REPLY_OK" : "REPLY_NG")
;
			_UTL_LOG_I ("replyData [%s]\n", (char*)(pReplyMsg->getData()));
		}
	}

	void onHandleNotify (CNotifyMessage *pNotifyMsg) override {
		_UTL_LOG_I ("%s\n", __PRETTY_FUNCTION__);
	}
};

int main (void)
{
//TODO
	sigset_t sigset;
	sigemptyset (&sigset);
	sigaddset (&sigset, SIGPIPE);
	sigprocmask (SIG_BLOCK, &sigset, NULL);


	// specify message handle thread pool num = 2
	CClMessageHandler *pHandler = new CClMessageHandler(2);

	CClient client ((const char*)"127.0.0.1", 65000, pHandler); // specified tcp port 65000

	// connect
	bool r = client.connectToServer();
	if (!r) {
		exit (EXIT_FAILURE);
	}
	client.startReceiver();


	uint8_t command = 0x01;
	char *p_data = (char*)"test";

	// async request  -> reply is handled by CClMessageHandler.
	CRequestMessage *pRequestMsg = new CRequestMessage (&client);
	g_id = pRequestMsg->generateId(); // for async reply id match
	pRequestMsg->sendAsync (&g_id, command, (uint8_t*)p_data, (int)strlen(p_data));
	delete pRequestMsg;
	pRequestMsg = NULL;

	// sync request
	CRequestMessage *pRequestMsgSync = new CRequestMessage (&client);
	pRequestMsgSync->sendSync (command, (uint8_t*)p_data, (int)strlen(p_data)); // request and wait rep
ly
	if (pRequestMsgSync->isReplyResultOK()) {
		_UTL_LOG_I ("REPLY_OK (sync)\n");
	} else {
		_UTL_LOG_I ("REPLY_NG (sync)\n");
	}
	_UTL_LOG_I ("replyData [%s]\n", (char*)(pRequestMsgSync->getData()));
	delete pRequestMsgSync;
	pRequestMsgSync = NULL;


	fgetc (stdin);


	// disconnect
	client.syncStopReceiver();
	client.disconnectFromServer();

	if (pHandler) {
		delete pHandler;
		pHandler = NULL;
	}

	exit (EXIT_SUCCESS);
}

Component diagram

component diagram

Class diagram

class diagram

Packet format

packet format

Platforms

Generic Linux will be ok. (confirmed worked on Ubuntu, Fedora)

About

socket library which can be used immediately (sock_stream) (unix_domain/inet_domain)

License:MIT License


Languages

Language:C++ 90.7%Language:Makefile 8.4%Language:Shell 0.6%Language:C 0.3%