asp.net - Making a Thread Safe socket class in C# -
i have question sockets
, concepts of thread safe
sockets. have 2 classes, server class , client class :
using system; using system.collections.generic; using system.linq; using system.net; using system.net.sockets; using system.text; using system.threading; using system.threading.tasks; // loosely inspired on http://msdn.microsoft.com/en-us/library/fx6588te.aspx namespace asynchronoussockets { class server { class stateobject { public socket connection = null; // note use small buffer size // example. you'd // larger buffer. small buffer size nicely // demonstrates getting entire message in multiple // pieces. public const int buffersize = 100000; public byte[] buffer = new byte[buffersize]; public int expectedmessagelength = 0; public int receivedmessagelength = 0; public byte[] message = null; } static manualresetevent acceptdone = new manualresetevent(false); const int listenport = 2500; static void main(string[] args) { console.out.writeline("this server"); ipendpoint localendpoint = new ipendpoint(ipaddress.any, listenport); socket listener = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp); try { listener.bind(localendpoint); listener.listen(100); while (true) { acceptdone.reset(); console.out.writeline("listening on port {0}", listenport); listener.beginaccept(new asynccallback(acceptcallback), listener); acceptdone.waitone(); } } catch (exception e) { console.writeline(e.message); } } static void acceptcallback(iasyncresult ar) { try { acceptdone.set(); socket listener = (socket)ar.asyncstate; socket handler = listener.endaccept(ar); stateobject state = new stateobject(); state.connection = handler; handler.beginreceive(state.buffer, 0, stateobject.buffersize, socketflags.none, new asynccallback(readcallback), state); } catch (exception e) { console.writeline(e.message); } } static void readcallback(iasyncresult ar) { try { stateobject state = (stateobject)ar.asyncstate; socket handler = state.connection; int read = handler.endreceive(ar); if (read > 0) { console.out.writeline("read {0} bytes", read); if (state.expectedmessagelength == 0) { // extract how data expect first 4 bytes // configure buffer sizes , copy received // part of message. state.expectedmessagelength = bitconverter.toint32(state.buffer, 0); state.message = new byte[state.expectedmessagelength]; array.constrainedcopy(state.buffer, 4, state.message, 0, math.min(stateobject.buffersize - 4, state.expectedmessagelength - state.receivedmessagelength)); state.receivedmessagelength += read - 4; } else { array.constrainedcopy(state.buffer, 0, state.message, state.receivedmessagelength, math.min(stateobject.buffersize, state.expectedmessagelength - state.receivedmessagelength)); state.receivedmessagelength += read; } // check if received entire message. if not // continue listening, else close connection // , reconstruct message. if (state.receivedmessagelength < state.expectedmessagelength) { handler.beginreceive(state.buffer, 0, stateobject.buffersize, socketflags.none, new asynccallback(readcallback), state); } else { handler.shutdown(socketshutdown.both); handler.close(); console.out.writeline("received message: \n"); console.out.writeline(encoding.utf8.getstring(state.message)); } } } catch (exception e) { console.writeline(e.message); } } } } using system; using system.collections.generic; using system.linq; using system.net; using system.net.sockets; using system.text; using system.threading; using system.threading.tasks; using system.io; using client; using system.management; // loosely inspired on http://msdn.microsoft.com/en-us/library/bew39x2a.aspx namespace asynchronoussockets { class program { static readonly ipaddress serverip = ipaddress.loopback; const int serverport = 2500; static manualresetevent connectdone = new manualresetevent(false); static manualresetevent senddone = new manualresetevent(false); static void main(string[] args) { console.out.writeline("this client"); console.out.writeline("write message send. end emtpy line start transmisison. \n"); string username = system.security.principal.windowsidentity.getcurrent().name; (int = 0; <= 10000; i++) { string message = datetime.now.tostring("dd-mm-yyyy hh:mm:ss") + " : message sended " + username + "."; console.out.writeline("sending message: ...\n"); console.out.write(message); console.out.write("\n"); thread.sleep(10); console.out.writeline("sleeping ...\n"); sendmessageasync(message); } console.out.writeline("sending finished " + username + "! \n"); } static void sendmessageasync(string message) { // initiate connecting server socket connection = connect(); // block thread until have connected // program continue doing other work // we've got nothing :) connectdone.waitone(); console.out.writeline("connected server"); // start sending data senddata(connection, message); senddone.waitone(); console.out.writeline("message sent"); } static socket connect() { try { ipendpoint serveraddress = new ipendpoint(serverip, serverport); socket client = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp); client.beginconnect(serveraddress, new asynccallback(connectcallback), client); return client; } catch (exception e) { console.writeline(e.message); return null; } } static void senddata(socket connection, string message) { try { byte[] data = encoding.utf8.getbytes(message); // store how data server should expect // in first 4 bytes of data we're going send byte[] head = bitconverter.getbytes(data.length); byte[] total = new byte[data.length + head.length]; head.copyto(total, 0); data.copyto(total, head.length); connection.beginsend(total, 0, total.length, 0, new asynccallback(sendcallback), connection); } catch (exception e) { console.out.writeline(e.message); } } private static void connectcallback(iasyncresult ar) { try { socket client = (socket)ar.asyncstate; client.endconnect(ar); connectdone.set(); } catch (exception e) { console.out.writeline(e.message); } } private static void sendcallback(iasyncresult ar) { try { socket client = (socket)ar.asyncstate; int bytes = client.endsend(ar); console.out.writeline("a total of {0} bytes sent server", bytes); senddone.set(); } catch (exception e) { console.out.writeline(e.message); } } } }
as can see client.exe
starts, if server.exe
running recieve messages sended client
class.
for (int = 0; <= 10000; i++) { string message = datetime.now.tostring("dd-mm-yyyy hh:mm:ss") + " : message sended " + username + "."; console.out.writeline("sending message: ...\n"); console.out.write(message); console.out.write("\n"); thread.sleep(10); console.out.writeline("sleeping ...\n"); sendmessageasync(message); }
and loop executed 10000 times pause between loops of 10 milliseconds. start 3 clients 3 places (different windows users logged on same time), , the server log :
...... 02-06-2014 11:24:30 : message sended mycomputer-pc\user1. listening on port 2500 listening on port 2500 listening on port 2500 read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 7 bytes received message: 02-06-2014 11:24:30 : message sended mycomputer-pc\user2. read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 7 bytes received message: 02-06-2014 11:24:30 : message sended mycomputer-pc\user3. listening on port 2500 listening on port 2500 read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 7 bytes received message: 02-06-2014 11:24:30 : message sended mycomputer-pc\user2. read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 7 bytes received message: 02-06-2014 11:24:30 : message sended mycomputer-pc\user3. read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 7 bytes received message: 02-06-2014 11:24:30 : message sended mycomputer-pc\user1. listening on port 2500 read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 8 bytes read 7 bytes received message: ......
after 3 clients stop, open log file in 'notepad++' , count following results :
count "mycomputer-pc\user1" => 8903
count "mycomputer-pc\user2" => 8464
count "mycomputer-pc\user3" => 8990
why this? data had been lost, should render 10.000 10.000 10.000 ...
how can solve this?
another thing want ask si how make socket thread safe.
edit
i getting log when socket refused
connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent sending message: ... 03-06-2014 09:35:58 : message sended mycomputer-pc\user1. sleeping ... connection.connected false connection.blocking true connected server request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied message sent
thank you.
the problem looks use of manualresetevent
s in client. remember, manualresetevent
must manually reset, otherwise waitone()
calls after event has been set()
return immediately. result, client not waiting socket connected before trying send data after first message sent, indicated following message saw logged when ran on machine:
a request send or receive data disallowed because socket not connected , (when sending on datagram socket using sendto call) no address supplied
try changing manualresetevent
s autoresetevent
s (which automatically reset after waitone()
returns true) in client, should resolve issue.
Comments
Post a Comment