multithreading - C# Issues with Multi-Threading and Socket -


first of all, want let know not new programming, should easier me :)

i having issues multi-threaded chat making in c# socket.

i have 3 threads :

  • void listensocketconnection : check socket connect. connected socket added list<>
  • void checkifclientstillconnectedthread : check if socket disconnected. disconnected socket removed list<>
  • void receivedatalistener : check if socket received data
    • here issue. if first or second thread remove socket list<>, 'foreach (clientmanager cmanager in clientslist)' raise exception.
    • here second issue. if socket disconnect during foreach, 'foreach clientmanager cmanager in clientslist)' raise exception : disposedexception

do have tips on how fix this?

here code :

using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; using system.net; using system.net.sockets; using system.componentmodel; using system.threading;  namespace jachat.library {     class socketserver     {         private socket socketserver;         private backgroundworker bwsocketconnectlistener;         private backgroundworker bwcheckifconnected;         private backgroundworker bwreceivedatalistener;         private list<clientmanager> clientslist;          #region constructor         public socketserver(int port)         {             clientslist = new list<clientmanager>();              socketserver = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp);             socketserver.bind(new ipendpoint(ipaddress.any, port));             socketserver.listen(100);              bwsocketconnectlistener = new backgroundworker();             bwsocketconnectlistener.dowork += new doworkeventhandler(listensocketconnection);             bwsocketconnectlistener.runworkerasync();              bwcheckifconnected = new backgroundworker();             bwcheckifconnected.dowork += checkifclientstillconnectedthread;             bwcheckifconnected.runworkerasync();              bwreceivedatalistener = new backgroundworker();             bwreceivedatalistener.dowork += receivedatalistener;             bwreceivedatalistener.runworkerasync();         }         #endregion          #region getter         public list<clientmanager> connectedclients         {                         {                 return clientslist;             }         }         #endregion          #region public methods         /// <summary>         /// parse , send command object targets         /// </summary>         public void sendcommand(command cmd)         {             backgroundworker test = new backgroundworker();             test.dowork += delegate {                 foreach(clientmanager cmanager in clientslist){                     cmanager.sendcommand(cmd);                 }             };             test.runworkerasync();         }          /// <summary>         /// disconnect , close socket         /// </summary>         public void disconnect()         {             socketserver.disconnect(false);             socketserver.close();             socketserver = null; //stop background worker         }         #endregion          #region private methods         private void listensocketconnection(object sender, doworkeventargs e)         {             while (socketserver != null)             {                 //get , wait new connection                 clientmanager newclientmanager = new clientmanager(socketserver.accept());                 clientslist.add(newclientmanager);                 onclientconnect.invoke(newclientmanager);             }         }          private void checkifclientstillconnectedthread(object sender, doworkeventargs e){             while(socketserver != null){                 for(int i=0;i<clientslist.count;i++){                     if(clientslist[i].socket.poll(10,selectmode.selectread) && clientslist[i].socket.available==0){                         clientslist[i].socket.close();                         onclientdisconnect.invoke(clientslist[i]);                         clientslist.remove(clientslist[i]);                         i--;                                             }                 }                 thread.sleep(5);             }         }          private void receivedatalistener(object unused1, doworkeventargs unused2){             while (socketserver != null){                 foreach (clientmanager cmanager in clientslist)                 {                     try                     {                         if (cmanager.socket.available > 0)                         {                             console.writeline("receive data listener 0");                             //read command's type.                             byte[] buffer = new byte[4];                             int readbytes = cmanager.socket.receive(buffer, 0, 4, socketflags.none);                             console.writeline("receive data listener 1");                             if (readbytes == 0)                                 break;                             console.writeline("receive data listener 2");                             commandtype cmdtype = (commandtype)(bitconverter.toint32(buffer, 0));                             console.writeline("receive data listener 3");                              //read sender ip size.                             buffer = new byte[4];                             readbytes = cmanager.socket.receive(buffer, 0, 4, socketflags.none);                             if (readbytes == 0)                                 break;                             int senderipsize = bitconverter.toint32(buffer, 0);                              //read sender ip.                             buffer = new byte[senderipsize];                             readbytes = cmanager.socket.receive(buffer, 0, senderipsize, socketflags.none);                             if (readbytes == 0)                                 break;                             ipaddress cmdsenderip = ipaddress.parse(system.text.encoding.ascii.getstring(buffer));                              //read sender name size.                             buffer = new byte[4];                             readbytes = cmanager.socket.receive(buffer, 0, 4, socketflags.none);                             if (readbytes == 0)                                 break;                             int sendernamesize = bitconverter.toint32(buffer, 0);                              //read sender name.                             buffer = new byte[sendernamesize];                             readbytes = cmanager.socket.receive(buffer, 0, sendernamesize, socketflags.none);                             if (readbytes == 0)                                 break;                             string cmdsendername = system.text.encoding.unicode.getstring(buffer);                              //read target ip size.                             string cmdtarget = "";                             buffer = new byte[4];                             readbytes = cmanager.socket.receive(buffer, 0, 4, socketflags.none);                             if (readbytes == 0)                                 break;                             int targetipsize = bitconverter.toint32(buffer, 0);                              //read command's target.                             buffer = new byte[targetipsize];                             readbytes = cmanager.socket.receive(buffer, 0, targetipsize, socketflags.none);                             if (readbytes == 0)                                 break;                             cmdtarget = system.text.encoding.ascii.getstring(buffer);                              //read command's metadata size.                             string cmdmetadata = "";                             buffer = new byte[4];                             readbytes = cmanager.socket.receive(buffer, 0, 4, socketflags.none);                             if (readbytes == 0)                                 break;                             int metadatasize = bitconverter.toint32(buffer, 0);                              //read command's meta data.                             buffer = new byte[metadatasize];                             readbytes = cmanager.socket.receive(buffer, 0, metadatasize, socketflags.none);                             if (readbytes == 0)                                 break;                             cmdmetadata = system.text.encoding.unicode.getstring(buffer);                              //create command object                             command cmd = new command(cmdtype, cmdsenderip, cmdsendername, ipaddress.parse(cmdtarget), cmdmetadata);                             this.oncommandreceived(cmd);                         }                     }                     catch (objectdisposedexception) {/*le socket s'est déconnectée pendant le each. ignore l'érreur et retourne dans le while*/ }                     catch (invalidoperationexception) { /* clientslist été modifié pendant le foreach et délanche une exception. retour while*/}                 }                             }             console.writeline("receive data listener closed");         }         #endregion          #region events         public delegate void onclientconnecteventhandler(clientmanager client);         /// <summary>         /// events invoked when client connect server         /// </summary>         public event onclientconnecteventhandler onclientconnect = delegate { };          public delegate void onclientdisconnecteventhandler(clientmanager client);         /// <summary>         /// events invoked when client disconnect server         /// </summary>         public event onclientdisconnecteventhandler onclientdisconnect = delegate { };          public delegate void oncommandreceivedeventhandler(command cmd);         /// <summary>         /// events invoked when command has been sent server         /// </summary>         public event oncommandreceivedeventhandler oncommandreceived = delegate { };         #endregion     } } 

  1. there multiple threads don't see synchronization. that's incorrect. use lock protect mutable shared state.
  2. instead of having central management of sockets, polling , checking of dataavailable, why don't use either 1 thread per socket or async io? way ever manage 1 socket @ time. no polling necessary. call read (or async version) , wait data arrive. better paradigm deal sockets. basically, if socket code contains dataavailable or polling, going against best-practices (and have bug somewhere). think how solve without using two. possible, , better.
  3. in receivedatalistener assume, if data available entire message available. that's wrong because tcp stream-oriented. can receive sent data in arbitrarily small chunks. going point (2) fixes this.

to elaborate on (2): actor model. 1 actor per socket. whether implement actor using thread, using async/await or using legacy async io not matter.

hope helps. feel free ask follow-up questions in comments below.


Comments

Popular posts from this blog

c++ - CryptStringToBinary API behavior -

java.util.scanner - How to read and add only numbers to array from a text file -

iphone - Three second countdown in cocos2d -