c# - TCP Server with bi-directional communication -
i have attempted create tcp service able achieve wish sadly getting stuck @ last hurdle.
the scenario: single server instance running 10 clients connected, client send command, , receive response. working fine. last scenario isn't working
when client issues "update" command, server should send message connected clients need something.
example comms:
1 client gettime -----> server client <----- time is... server 2 client update ------> server client <------- ack server client <------- doupdate server client b <------- doupdate server client c <------- doupdate server
comms 1 abover works, because of call send , call reeive, comms 2 cannot workout how can achieve this, @ least not without opening second port communication isn't ideal.
current attempt based on microsoft article
server
class program { public static int main(string[] args) { asynchronoussocketlistener.startlistening(); return 0; } } public class stateobject { // client socket. public socket worksocket = null; // size of receive buffer. public const int buffersize = 1024; // receive buffer. public byte[] buffer = new byte[buffersize]; // received data string. public stringbuilder sb = new stringbuilder(); } public class asynchronoussocketlistener { // thread signal. public static manualresetevent alldone = new manualresetevent(false); public static void startlistening() { // data buffer incoming data. //var bytes = new byte[1024]; // establish local endpoint socket. // dns name of computer // running listener "host.contoso.com". //??iphostentry iphostinfo = dns.resolve(dns.gethostname()); //??ipaddress ipaddress = iphostinfo.addresslist[0]; //??ipendpoint localendpoint = new ipendpoint(ipaddress, 3030); // create tcp/ip socket. var listener = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp); // bind socket local endpoint , listen incoming connections. try { listener.bind(new ipendpoint(ipaddress.any, 3030)); //listener.bind(localendpoint); listener.listen(100); while (true) { // set event nonsignaled state. alldone.reset(); // start asynchronous socket listen connections. console.writeline("waiting connection..."); listener.beginaccept((acceptcallback), listener); // wait until connection made before continuing. alldone.waitone(); } } catch (exception e) { console.writeline(e.tostring()); } console.writeline("\npress enter continue..."); console.read(); } public static void acceptcallback(iasyncresult ar) { // signal main thread continue. alldone.set(); // socket handles client request. var listener = (socket)ar.asyncstate; socket handler = listener.endaccept(ar); // create state object. var state = new stateobject {worksocket = handler}; handler.beginreceive(state.buffer, 0, stateobject.buffersize, 0, readcallback, state); } public static void readcallback(iasyncresult ar) { // retrieve state object , handler socket // asynchronous state object. var state = (stateobject)ar.asyncstate; socket handler = state.worksocket; // read data client socket. int bytesread = handler.endreceive(ar); if (bytesread > 0) { // there might more data, store data received far. state.sb.append(encoding.ascii.getstring( state.buffer, 0, bytesread)); // check end-of-file tag. if not there, read // more data. var content = state.sb.tostring(); if (content.indexof("<eof>", stringcomparison.ordinal) > -1) { // data has been read // client. display on console. console.writeline("read {0} bytes socket. \n data : {1}", content.length, content); // echo data client. send(handler, content); } else { // not data received. more. handler.beginreceive(state.buffer, 0, stateobject.buffersize, 0, readcallback, state); } } } private static void send(socket handler, string data) { // convert string data byte data using ascii encoding. var bytedata = encoding.ascii.getbytes(data); // begin sending data remote device. handler.beginsend(bytedata, 0, bytedata.length, 0, sendcallback, handler); } private static void sendcallback(iasyncresult ar) { try { // retrieve socket state object. var handler = (socket)ar.asyncstate; // complete sending data remote device. int bytessent = handler.endsend(ar); console.writeline("sent {0} bytes client.", bytessent); handler.shutdown(socketshutdown.both); handler.close(); } catch (exception e) { console.writeline(e.tostring()); } } /* public static int main(string[] args) { startlistening(); return 0; } * */ }
client code
class program { public static int main(string[] args) //static void main(string[] args) { console.title = "client "; asynchronousclient.startclient(); console.readline(); return 0; } } public class stateobject { // client socket. public socket worksocket = null; // size of receive buffer. public const int buffersize = 256; // receive buffer. public byte[] buffer = new byte[buffersize]; // received data string. public stringbuilder sb = new stringbuilder(); } public class asynchronousclient { // port number remote device. private const int port = 3030; // manualresetevent instances signal completion. private static readonly manualresetevent connectdone = new manualresetevent(false); private static readonly manualresetevent senddone = new manualresetevent(false); private static readonly manualresetevent receivedone = new manualresetevent(false); // response remote device. private static string _response = string.empty; public static void startclient() { // connect remote device. try { // establish remote endpoint socket. // name of // remote device "host.contoso.com". //iphostentry iphostinfo = dns.resolve("host.contoso.com"); //??iphostentry iphostinfo = dns.resolve("localhost"); //??ipaddress ipaddress = iphostinfo.addresslist[0]; //??ipendpoint remoteep = new ipendpoint(ipaddress, port); // create tcp/ip socket. var client = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp); // connect remote endpoint. //client.beginconnect(remoteep, //new asynccallback(connectcallback), client); var remoteep = new ipendpoint(ipaddress.parse("127.0.0.1"), port); client.beginconnect(remoteep, connectcallback, client); connectdone.waitone(); // set receive thread can receive, doesn't work intended //var thread = new thread(() => readthread(client)); //thread.start(); // send test data remote device. send(client, "this test<eof>"); senddone.waitone(); //test remove // receive response remote device. receive(client); receivedone.waitone(); // write response console. console.writeline("response received : {0}", _response); // release socket. //client.shutdown(socketshutdown.both); //client.close(); } catch (exception e) { console.writeline(e.tostring()); } } // doesn't work expected private static void readthread(object ar) { var client = (socket)ar; while (true) { receive(client); receivedone.waitone(); // write response console. console.writeline("response received : {0}", _response); } } private static void connectcallback(iasyncresult ar) { try { // retrieve socket state object. var client = (socket)ar.asyncstate; // complete connection. client.endconnect(ar); console.writeline("socket connected {0}", client.remoteendpoint); // signal connection has been made. connectdone.set(); } catch (exception e) { console.writeline(e.tostring()); } } private static void receive(socket client) { try { // create state object. var state = new stateobject {worksocket = client}; // begin receiving data remote device. client.beginreceive(state.buffer, 0, stateobject.buffersize, 0, receivecallback, state); } catch (exception e) { console.writeline(e.tostring()); } } private static void receivecallback(iasyncresult ar) { try { // retrieve state object , client socket // asynchronous state object. var state = (stateobject)ar.asyncstate; socket client = state.worksocket; // read data remote device. int bytesread = client.endreceive(ar); if (bytesread > 0) { // there might more data, store data received far. state.sb.append(encoding.ascii.getstring(state.buffer, 0, bytesread)); // rest of data. client.beginreceive(state.buffer, 0, stateobject.buffersize, 0, receivecallback, state); } else { // data has arrived; put in response. if (state.sb.length > 1) { _response = state.sb.tostring(); } // signal bytes have been received. receivedone.set(); } } catch (exception e) { console.writeline(e.tostring()); } } private static void send(socket client, string data) { // convert string data byte data using ascii encoding. var bytedata = encoding.ascii.getbytes(data); // begin sending data remote device. client.beginsend(bytedata, 0, bytedata.length, 0, sendcallback, client); } private static void sendcallback(iasyncresult ar) { try { // retrieve socket state object. var client = (socket)ar.asyncstate; // complete sending data remote device. int bytessent = client.endsend(ar); console.writeline("sent {0} bytes server.", bytessent); // signal bytes have been sent. senddone.set(); } catch (exception e) { console.writeline(e.tostring()); } } /* public static int main(string[] args) { startclient(); return 0; } */ }
previous system worked
server:
class program { private static byte[] buffer = new byte[1024]; public static socket _serversocket = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp); public static list<socket> clientsockets = new list<socket>(); static void main(string[] args) { console.title = "server, " + clientsockets.count + " clients connected"; setupserver(); console.readline(); } public static void setupserver() { console.writeline("setting server..."); _serversocket.bind(new ipendpoint(ipaddress.any, 3030)); _serversocket.listen(10); _serversocket.beginaccept(acceptcallback, null); console.readline();// stops cmd closing } public static void acceptcallback(iasyncresult ar) { socket socket = _serversocket.endaccept(ar); if (!clientsockets.contains(socket)) clientsockets.add(socket); ipendpoint remoteipendpoint = socket.remoteendpoint ipendpoint; console.writeline(remoteipendpoint.address); console.writeline("client connected"); console.title = "server, " + clientsockets.count + " clients connected"; socket.beginreceive(buffer, 0, buffer.length, socketflags.none, recievecallback, socket); _serversocket.beginaccept(acceptcallback, null); } private static void recievecallback(iasyncresult ar) { var socket = (socket)ar.asyncstate; int received = socket.endreceive(ar); var databuff = new byte[received]; array.copy(buffer, databuff, received); string s = encoding.ascii.getstring(databuff); console.writeline("text received: " + s); string response = string.empty; switch (s.tolower()) { case "get time": response = datetime.now.tolongtimestring(); break; case "hello": response = "olleh"; break; case "update clients": response = ""; senddata("ack", socket); doupdateclients(); break; default: response = "invavlid request"; break; } senddata(response, socket); } private static void senddata(string data, socket socket) { byte[] data = encoding.ascii.getbytes(data); socket.beginsend(data, 0, data.length, socketflags.none, sendcallback, socket); socket.beginreceive(buffer, 0, buffer.length, socketflags.none, recievecallback, socket); } private static void doupdateclients() { // need send update message clients var upd = new thread((updateclients)); upd.start(); } private static void updateclients() { thread.sleep(5000); foreach (var sock in clientsockets) { senddata("updateclients", sock); } } private static void sendcallback(iasyncresult ar) { var socket = (socket)ar.asyncstate; socket.endsend(ar); } // } }
client:
class program { private static byte[] buffer = new byte[1024]; public static socket _clientsocket = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp); static void main(string[] args) { console.title = "client "; loopconnect(); //receiveloopstart(); //_clientsocket.listen(10); sendloop(); console.readline(); } private static void loopconnect() { while (!_clientsocket.connected) { try { _clientsocket.connect(ipaddress.parse("127.0.0.1"), 3030); } catch (socketexception se) { } } console.writeline("connected"); } private static void receiveloopstart() { //_clientsocket.bind(new ipendpoint(ipaddress.any, 3030)); //_clientsocket.listen(10); _clientsocket.beginaccept(acceptcallback, null); thread receivethread = new thread(receiveloop); receivethread.start(); } private static void receiveloop() { _clientsocket.beginreceive(buffer, 0, buffer.length, socketflags.none, recievecallback, _clientsocket); _clientsocket.beginaccept(acceptcallback, null); } private static void recievecallback(iasyncresult ar) { int received = _clientsocket.endreceive(ar); var databuff = new byte[received]; array.copy(buffer, databuff, received); string s = encoding.ascii.getstring(databuff); console.writeline("text received: " + s); string response = string.empty; switch (s.tolower()) { case "get time": response = datetime.now.tolongtimestring(); break; case "hello": response = "olleh"; break; default: response = "invavlid request"; break; } } public static void acceptcallback(iasyncresult ar) { socket socket = _clientsocket.endaccept(ar); console.writeline("client connected"); socket.beginreceive(buffer, 0, buffer.length, socketflags.none, recievecallback, socket); _clientsocket.beginaccept(acceptcallback, null); } private static void sendloop() { while (true) { console.write("enter request: "); string req = console.readline(); var buffer = encoding.ascii.getbytes(req); _clientsocket.send(buffer); var tempbuff = new byte[1024]; int rec = _clientsocket.receive(tempbuff); var data = new byte[rec]; array.copy(tempbuff, data, rec); console.writeline("received: " + encoding.ascii.getstring(data)); } } } }
i don't have example sleeve here in c# need learn use select api.
need single thread this. use same thread process sockets in use @ point in time.
if nobody connected have listening socket. , use select api watch happens on socket. select blocking call when no timeout specified. if data available, means can call accept. result of accept know socket. use 2 sockets in select. again select block until 1 of sockets has data. perhaps listening socket again, socket after calling accept. use 3 sockets in select. suppose 1 of accept sockets have data available see using select api properly. , can use of sockets send on it, except of course listening socket not intended sending.
more info can found here : http://www.codeproject.com/articles/20066/a-scalable-client-server-using-select-socket-funct
it uses explained , gives more elaborate explanations too.
Comments
Post a Comment