locked
C# Socket send / receive Problem RRS feed

  • Question

  • New to C#, I am trying to create a console application which receives messages from an intercom via serial interface and passes them via sockets to a server. Also the server needs to send answers the same way to the intercom. I got to the point that my program can read the intercom and pass messages to the server continuously. However I could not implement the reception of messages from the server neither in the main thread nor in a separate one. I think this should be performed in a separate thread. But as soon as I activate the receive thread, even the sending gets blocked and nothing works. Can somebody please help me? Thank you. My source code:

    using System; using System.Text; using System.IO; using System.IO.Ports; using System.Net; using System.Net.Sockets; using System.Threading; namespace CommSlave { class Program { public static string sParkhaus = null; public static SerialPort SerPort = new SerialPort(); public static Socket Sock = null; public static string sIPAdr = null; public static int nTCPPort = 0; public static string sInMsg; public static string sInMsgOld; public static string sOutMsg; public static byte[] cBuffer = new byte[20]; public static int nChars; public static void Main(string[] args) { string cFilename = "C:\\SLAVE.INI"; string cContent = ""; string cParm = ""; if (File.Exists(cFilename)) { StreamReader INIFile = new StreamReader(cFilename, System.Text.Encoding.Default); cContent = INIFile.ReadToEnd(); INIFile.Close(); string[] result = cContent.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string sItem in result) { cParm = sItem; switch (cParm.Substring(0,4)) { case "park": sParkhaus = cParm.Substring(9); break; case "port": SerPort.PortName = cParm.Substring(5); break; case "baud": SerPort.BaudRate = Convert.ToInt32(cParm.Substring(9)); break; case "pari": switch (cParm.Substring(7)) { case "NONE": SerPort.Parity = Parity.None; break; case "ODD": SerPort.Parity = Parity.Odd; break; case "EVEN": SerPort.Parity = Parity.Even; break; } break; case "data": SerPort.DataBits = Convert.ToInt32(cParm.Substring(9)); break; case "stop": switch (cParm.Substring(9)) { case "NONE": SerPort.StopBits = StopBits.None; break; case "ONE": SerPort.StopBits = StopBits.One; break; case "TWO": SerPort.StopBits = StopBits.Two; break; case "ONEPOINTFIVE": SerPort.StopBits = StopBits.OnePointFive; break; } break; case "ipad": sIPAdr = (cParm.Substring(6)); break; case "tcpp": nTCPPort = Convert.ToInt32(cParm.Substring(8)); break; } } } SerPort.DataReceived += new SerialDataReceivedEventHandler(ReceiveFromIntercom); SerPort.Open(); IPAddress ipAdr = IPAddress.Parse(sIPAdr); IPEndPoint ipEo = new IPEndPoint(ipAdr, nTCPPort); Sock = new Socket(ipEo.AddressFamily, SocketType.Stream, ProtocolType.Tcp); try { Sock.Connect(ipEo); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.ReadLine(); } // Thread ctThread = new Thread(ReceiveFromMaster); // ctThread.Start(); while (true) { } } public static void ReceiveFromMaster() { while (true) { try { nChars += Sock.Receive(cBuffer, nChars, SocketFlags.None); sOutMsg = Encoding.UTF8.GetString(cBuffer, 0, cBuffer.Length); SendToIntercom(sOutMsg); } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.WouldBlock || ex.SocketErrorCode == SocketError.IOPending || ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable) { Thread.Sleep(30); } else throw ex; } } } private static void ReceiveFromIntercom(object sender, SerialDataReceivedEventArgs e) { sInMsg = SerPort.ReadExisting(); if (sInMsg.Length == 20) { if (sInMsg.Equals(sInMsgOld)) { } else { sInMsgOld = sInMsg; sInMsg = sInMsg.Substring(1, 18); // Console.WriteLine(cMeldung); SendToMaster(); } } } private static void SendToMaster() { if (Sock.Connected) { try { string request = sInMsg + sParkhaus + "\r\n"; Byte[] bytesSent = Encoding.ASCII.GetBytes(request); Sock.Send(bytesSent, bytesSent.Length, SocketFlags.None); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.ReadLine(); } } } public static void SendToIntercom(string cOutMsg) { SerPort.Write(sOutMsg); } } }


    • Moved by Lisa Zhu Tuesday, September 4, 2012 5:45 AM network related (From:Visual C# General)
    Sunday, September 2, 2012 3:55 PM

All replies

  • If the server doesn't answer immediately after the client sends the message I would suggest a second thread both at the server and at the client where you make a second client-server connection with changed roles (client -> server & server -> client).
    So the communication will work but it's a bad solutions if many clients are connecting to the server.
    Sunday, September 2, 2012 5:12 PM
  • Hello Mr. Jochen,

    if I understand you correctly, you suggest to handle both directions of the communication separately from the main thread in two different threads, whereas always the sender is the "client" and the other side of the communication is the "server". Thank you for your suggestion, I will try this. The server has to handle only this one client, no other ones, so no workload problems can occur. Can the two separate communication lines use the same port? Thank you.

    Sunday, September 2, 2012 6:00 PM
  • I have two suggestions.

    1) First ist down and developing an archecture of how the system is going to work.  Determine if you are going to impliments syncrhonous Read/Write (blocking) or aysnchronous Read/Write (non blocking) for both the serial interface and the TCP interface.

    2) You don't need to use threads for your application.  Instead I usually develope a seperate class for my serial com interface and my TCP code.  When you use non blocking reads in both both the serial port class and TCP class you will have the equivalent to having two threads.  Threads and the ethernet interface both run off of the Timer Tick Service and get time shared by the Windows operating system exactly the same.


    jdweng

    Sunday, September 2, 2012 7:02 PM
  • Hi Z2803

    There shouldn't be any issues with communication over 2 different channels.

    As Joel suggested, seggregate your code into 2 classes (one that handles intercom communication & and handling TCP/IP comm) then you will have a better idea of what's failing.

    For TCP/IP implementation, you can use this library.

    It takes care of the TCP/IP communication hassels.


    .NET Maniac -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    Monday, September 3, 2012 4:43 AM
  • Hi Z2803 ,

    From your description , I ‘d like to move this post to  the most related forum .

    There has more  experts in this aspect  , so you may have more luck getting answers .

    Thanks for your understanding .

    Regards ,


    Lisa Zhu [MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, September 4, 2012 5:44 AM
  • What happens if you use this code:

    //SerPort.DataReceived += new SerialDataReceivedEventHandler(ReceiveFromIntercom); SerPort.Open(); _serStrm = SerPort.BaseStream; IPAddress ipAdr = IPAddress.Parse(sIPAdr); IPEndPoint ipEo = new IPEndPoint(ipAdr, nTCPPort); _tcpCli = new TcpClient(ipEo.AddressFamily); try { _tcpCli.Connect(ipEo); _peer = _tcpCli.GetStream(); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.ReadLine(); } ThreadPool.QueueUserWorkItem(CopyFromSerialToSocket); try { CopyFromSocketToIntercom(); } finally {
                    // Socket disconnected close all
    _peer.Close(); SerPort.Close(); } } private static void CopyFromSocketToIntercom() { CopyStream(_peer, _serStrm); } private static void CopyFromSerialToSocket(object state) { try { CopyStream(_serStrm, _peer); } finally { // Serial Port broken somehow, disconnect from the socket. _peer.Close(); } } /// <summary> /// Block, reading from <paramref name="from"/> and writing to /// <paramref name="to"/>. /// </summary> /// - /// <remarks> /// <para>Will return when we reach the End of Stream of /// <paramref name="from"/>. Will exit with an error in all other cases. /// </para> /// </remarks> /// - /// <param name="from">Source <see cref="T:System.IO.Stream"/>. /// </param> /// <param name="to">Destination <see cref="T:System.IO.Stream"/>. /// </param> private static void CopyStream(Stream from, Stream to) { var buf = new byte[2 * 1024]; while (true) { int readLen = from.Read(buf, 0, buf.Length); if (readLen == 0) { // EoF break; } to.Write(buf, 0, readLen); }//while }

    .


    http://www.alanjmcf.me.uk/ Please follow-up in the newsgroup. If I help, please vote and/or mark the question answered. Available for contract programming.


    Wednesday, September 5, 2012 9:36 AM