⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpservice.cpp

📁 贡献一份commoncpp2,有兴趣的可以研究一下
💻 CPP
字号:
//// tcpservice.cpp////  Copyright 2000 - Gianni Mariani <gianni@mariani.ws>////  An example of a simple chatty server using CommonC++.////  This simple application basically operates as a//  very simple chat system. From a telnet session//  on localhost:3999 , any messages typed from a telnet//  client are written to all participating sessions.////  This is free software licensed under the terms of the GNU//  Public License////  This example:////  This demostrates a simple threaded server, actually,//  the sessions are not all threaded though they could be//  if that's what you wanted.	Basically it demonstrates the//  use of SocketService, SocketPorts and Threads.////  For those familiar with Unix network programming, SocketService//  basically encapsulates all the work to communicate with//  the select() or poll() system calls.  SocketPorts are//  basically encapsulations of sessions or open file descriptors.////  Anyhow, this example is a very simple echo server but//  it echos to all connected clients.	So it's a poor man's//  IRC !  You connect via telnet to localhost port 3999 and//  it will echo to all other connected clients what you type in !//#include <cc++/socketport.h>#include <iostream>// For starters, we need a thread safe list, we'll make one// out of the STL list<> template -//  http://www.sgi.com/Technology/STL/index.html//// Thread safe list class//#include <list>#ifdef	CCXX_NAMESPACESusing namespace std;using namespace ost;#endifclass ts_list_item;typedef list<ts_list_item *> ts_list;// a list head - containing a list and a Mutex.// It would be really nice to teach stl to do this.class ts_list_head {public:    // No point inheriting, I'd have to implement    // alot of code. We'll hold off on that exercise.    // Using the CommonC++ Mutex class.    Mutex		    linkmutex;    // And the STL template.    ts_list		    list_o_items;    // Not nessasary, but nice to be explicit.    ts_list_head()	: linkmutex(), list_o_items()    {    }    // This thing knows how to remove and insert items.    void RemoveListItem( ts_list_item * li );    void InsertListItem( ts_list_item * li );    // And it knows how to notify that it became empty    // or an element was deleted and it was the last one.    virtual void ListDepleted()    {    }    virtual ~ts_list_head()    {    }};// This item knows how to remove itself from the// list it belongs to.class ts_list_item {public:    ts_list::iterator	   linkpoint;    ts_list_head	  * listhead;    virtual ~ts_list_item()    {	listhead->RemoveListItem( this );    }    ts_list_item( ts_list_head * head )    {	listhead = head;	head->InsertListItem( this );    }};void ts_list_head::RemoveListItem( ts_list_item * li ){    bool    is_empty;    linkmutex.enterMutex();    list_o_items.erase( li->linkpoint );    is_empty = list_o_items.empty();    linkmutex.leaveMutex();    // There is a slim possibility that at this time    // we recieve a connection.    if ( is_empty ) {	ListDepleted();    }}void ts_list_head::InsertListItem( ts_list_item * li ){    linkmutex.enterMutex();    list_o_items.push_front( li );    li->linkpoint = list_o_items.begin();    linkmutex.leaveMutex();}// ChatterSession operates on the individual connections// from clients as are managed by the SocketService// contained in CCExec.  ChatterThread simply waits in// a loop to create these, listening forever.//// Even though the SocketService contains a list of// clients it serves, it may actually serve more than// one type of session so we create our own list by// inheriting the ts_list_item.//class ChatterSession :    public virtual SocketPort,    public virtual ts_list_item{public:	enum { size_o_buf = 2048 };    // Nothing special to do here, it's all handled    // by SocketPort and ts_list_item    virtual ~ChatterSession()    {	cerr << "ChatterSession deleted !\n";    }    // When you create a ChatterSession it waits to accept a    // connection.  This is done by it's own    ChatterSession(	TCPSocket      & server,	SocketService	* svc,	ts_list_head	* head    ) :	SocketPort( NULL, server ),	ts_list_item( head )    {	cerr << "ChatterSession Created\n";	tpport_t port;	InetHostAddress ia = getPeer( & port );	cerr << "connecting from " << ia.getHostname() <<	":" << port << endl;	// Set up non-blocking reads	setCompletion( false );	// Set yerself to time out in 10 seconds	setTimer( 100000 );	attach(svc);    }    //    // This is called by the SocketService thread when it the    // object has expired.    //    virtual void expired()    {	// Get outa here - this guy is a LOOSER - type or terminate	cerr << "ChatterSession Expired\n";	delete this;    }    //    // This is called by the SocketService thread when it detects    // that there is somthing to read on this connection.    //    virtual void pending()    {	// Implement the echo	cerr << "Pending called\n";	// reset the timer	setTimer( 100000 );	try {	    int    len;	    unsigned int total = 0;	    char    buf[ size_o_buf ];	    while ( (len = receive(buf, sizeof(buf) )) > 0 ) {		total += len;		cerr << "Read '";		cerr.write( buf, len );		cerr << "'\n";		// Send it to all the sessions.		// We probably don't really want to lock the		// entire list for the entire time.		// The best way to do this would be to place the		// message somewhere and use the service function.		// But what are examples for ?		bool sent = false;		listhead->linkmutex.enterMutex();		for (		   ts_list::iterator iter = listhead->list_o_items.begin();		   iter != listhead->list_o_items.end();		   iter ++		) {		   ChatterSession * sess =		    dynamic_cast< ChatterSession * >( * iter );		   if ( sess != this ) {		    sess->send( buf, len );		    sent = true;		   }		}		listhead->linkmutex.leaveMutex();		if ( ! sent ) {		   send(		    ( void * ) "No one else listening\n",		    sizeof( "No one else listening\n" ) - 1		   );		   send( buf, len );		}	    }	    if (total == 0)	    {		cerr << "Broken connection!\n" << endl;		delete this;	    }	}	catch ( ... )	{	    // somthing wrong happened here !	    cerr << "Socket port write sent an exception !\n";	}    }    virtual void disconnect()    {	// Called by the SocketService thread when the client	// hangs up.	cerr << "ChatterSession disconnected!\n";	delete this;    }};class ChatterThread;//// This is the main application object containing all the// state for the application.  It uses a SocketService object// (and thread) to do all the work, however, that object could// theoretically be use by more than one main application.//// It creates a ChatterThread to sit and wait for connections// from clients.class CCExec : public virtual ts_list_head {public:    SocketService	    * service;    ChatterThread	       * my_Chatter;    Semaphore		      mainsem[1];    CCExec():my_Chatter(NULL)    {	service = new SocketService( 0 );    }    virtual void ListDepleted();    // These methods defined later.    virtual ~CCExec();    int RunApp( char * hn = "localhost" );};//// ChatterThread simply creates ChatterSession all the time until// it has an error.  I suspect you could create as many of these// as the OS could take.//class ChatterThread : public virtual TCPSocket, public virtual Thread {public:    CCExec		* exec;    void run ()    {	while ( 1 ) {	    try {		// new does all the work to accept a new connection		// attach itself to the SocketService AND include		// itself in the CCExec list of sessions.		new ChatterSession(		   * ( TCPSocket * ) this,		   exec->service,		   exec		);	    }	    catch ( ... )	    {		// Bummer - there was an error.		cerr << "ChatterSession create failed\n";		exit();	    }	}    }    ChatterThread(	InetHostAddress & machine,	int	      port,	CCExec	       * inexec    ) : TCPSocket( machine, port ),	Thread(),	exec( inexec )    {	    start();    }};//// Bug here, this should go ahead and shut down all sessions// for application.  An exercise left to the reader.CCExec::~CCExec(){    // MUST delete my_Chatter first or it may end up using    // a deleted service.    if ( my_Chatter ) delete my_Chatter;    // Delete whatever is left.    delete service;}//// Run App would normally read some config file or take some// parameters about which port to connect to and then// do that !int CCExec::RunApp( char * hn ){    // which port ?    InetHostAddress machine( hn );    if ( machine.isInetAddress() == false ) {	cerr << "machine is not address" << endl;    }    cerr << "machine is " << machine.getHostname() << endl;    // Start accepting connections - this will bind to the    // port as well.    try {	my_Chatter = new ChatterThread(	    machine,	    3999,	    this	);    }    catch ( ... )    {	cerr << "Failed to bind\n";	return false;    }        return true;}// When there is no one else connected - terminate !void CCExec::ListDepleted(){    mainsem->post();}int main( int argc, char ** argv ){    CCExec	* server;    server = new CCExec();    // take the first command line option as a hostname    // to listen to.    if ( argc > 1 ) {	server->RunApp( argv[ 1 ] );    } else {	server->RunApp();    }    server->mainsem->wait();    delete server;    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -