2013-05-11 68 views
2

我有一个套接字连接,并且通过这个套接字发送数据。我连接的服务器会回复我的数据的每一个正确的发送。我收到了该消息,因此我收到了每封邮件的答案。有时候服务器喜欢保留一段消息几秒钟,或者按照不同的顺序发送消息。我的解决方案是产生一个线程,让它绕接收函数旋转。但是,使用MSDN上的套接字示例,我有适合。他们使用简单的do/while循环结构。当我这样做时,我得到了混乱的回复,和/或不完整的数据。这是为了做家庭作业,所以我必须手工编写客户端,而不是仅仅使用更简单的解决方案。这个代码可能有问题吗?我在它的眼前这么久,我觉得我失去了一些东西简单:C#套接字接收线程

private static void ReceiveThread(Socket sock, ReceiverClass rc) 
{ 
    // Create a socket and pass in parameter converted from object socket 
    int receivedBytes = 0; 

    do 
    { 
     // receive data from socket 
     receivedBytes = sock.Receive(rc.buffer); 
     byte[] formattedMsg = new byte[receivedBytes]; 
     Array.Copy(rc.buffer, formattedMsg, receivedBytes); 
     rc.sb.Append("<LF><CR>" + System.Text.Encoding.ASCII.GetString(formattedMsg) + "\r\n"); 
    } 
    while (receivedBytes > 0); 
} 

编辑,并称滋生接收线程功能。 (这是太长时间,但我打算使它敢时,我得到了愚蠢的事情工作):

public void SendData(Socket sock) 
    { 
     // Set socket timeout 
     sock.ReceiveTimeout = 4000; 

     // Prepare file for IO operations 
     string path = @"c:\Logs\Lab2.Scenario3.WurdingerO.txt"; 
     StreamWriter logWrite = File.AppendText(path); 

     // Get local ip address: 
     IPAddress ip = Dns.GetHostAddresses(Dns.GetHostName()).Where(address => address.AddressFamily == AddressFamily.InterNetwork).First(); 
     string portNum = ((IPEndPoint)sock.LocalEndPoint).Port.ToString(); 

     // response time for scenario 2 and 3 
     int responseTime = 0; 

     // Set up Stopwatch to keep track of time 
     Stopwatch stpWatch = new Stopwatch(); 
     stpWatch.Start(); 

     // setup for logging class 
     ReceiverClass rc = new ReceiverClass(); 

     // setup receiving thread 
     Thread receiveThread = new Thread(delegate() 
      { 
       ReceiveThread(sock, rc); 
      }); 
     receiveThread.Start(); 

     // Counter to call client operations 
     for (int i = 0; i < MESSAGE_COUNT; i++) 
     { 
      string msTime = Convert.ToString(stpWatch.ElapsedMilliseconds); 
      if (msTime.Length > 10) 
      { 
       string newMSTime = ""; 

       for (int t = 9; t >= 0; t++) 
       { 
        newMSTime += msTime[t]; 
       } 
       msTime = newMSTime; 
      } 

      Classes.RequestBuilder reqB = new Classes.RequestBuilder(); 

      byte[] sendMsg; 

      switch (scenarioNo) 
      { 
       case 1: 
        sendMsg = reqB.MessageBuildScenarioOne(sock, msTime, 
         ip.ToString(), portNum, serverPort, serverIP, i); 
        break; 
       case 2: 
        // set up response time delay 
        switch (i) 
        { 
         case 1: 
          responseTime = 1000; 
          break; 
         case 3: 
          responseTime = 3000; 
          break; 
         default: 
          responseTime = 0; 
          break; 
        } 

        sendMsg = reqB.MessageBuildScenarioTwo(sock, msTime, 
         ip.ToString(), portNum, serverPort, serverIP, i, responseTime); 

        break; 
       case 3: 
        // set up response time delay 
        switch (i) 
        { 
         case 1: 
          responseTime = 1000; 
          break; 
         case 3: 
          responseTime = 3000; 
          break; 
         default: 
          responseTime = 0; 
          break; 
        } 

        sendMsg = reqB.MessageBuildScenarioThree(sock, msTime, 
         ip.ToString(), portNum, serverPort, serverIP, i, responseTime); 

        break; 
       default: 
        sendMsg = reqB.MessageBuildScenarioOne(sock, msTime, 
         ip.ToString(), portNum, serverPort, serverIP, i); 

        break; 
      } 

      try 
      { 
       sock.Send(sendMsg); 
      } 
      catch (Exception ex) 
      { 
       System.Windows.Forms.MessageBox.Show(ex.Message); 
      } 
     } 

     // Socket shutdown 
     sock.Shutdown(SocketShutdown.Send); 

     receiveThread.Join(); 

     sock.Shutdown(SocketShutdown.Receive); 

     string date = System.DateTime.Now.ToString("MMddyyyy"); 
     string time = System.DateTime.Now.ToString("HHmmss"); 

     logWrite.Write(rc.sb.ToString()); 
     logWrite.Write(date + "|" + time + "|0|0|"); 

     // Close log file 
     logWrite.Close(); 
     System.Windows.Forms.MessageBox.Show("Finished"); 
    } 

编辑: 我把睡眠计时器在发送操作后,并且固定我跑的问题成。 谢谢!

+0

构建它们时,套接字类型或协议是什么? – Ribose 2013-05-11 22:21:05

+0

你的代码似乎没问题,但不知道代码的其他部分,这很难回答。 – I4V 2013-05-11 22:42:30

+0

“我在发送操作之后放置了一个睡眠定时器,并解决了问题”可能不是固定的。睡眠掩盖了这个问题,所以在99%的情况下它不会发生。它仍然会以1%的速度失败,因为它看起来像是比赛条件。 – usr 2013-05-12 10:30:16

回答

0

我想我有类似的问题。

我正在使用Socket类发送JSON字符串,并且突然JSON.NET会抛出异常。我检查了字符串,并且看到正在处理2个JSON(根)对象。然后我抛出一个最小的例子,发现套接字将存储*任何未读数据(未读=否.Receive已被调用,而.Receive将清除存储)。

*隐藏:我不确定这是否是正确的术语。这对我有意义。

这是我的测试。如果你想运行它,创建一个新的测试类并安装XUnit。

/// <summary> 
/// Testing Net Sockets.. 
/// </summary> 
/// <author>Jeff Hansen</author> 
public class SocketTests 
{ 
    /// <summary> 
    /// The local endpoint for the server. There's no place like 127.0.0.1 
    /// </summary> 
    private IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1337); 

    /// <summary> 
    /// Tests that a call to .Receive will return all unread data. 
    /// </summary> 
    /// <author>Jeff Hansen</author> 
    [Fact] 
    public void ReceiveWillReadAllUnreadData() 
    { 
     // We expect to receive double data. 
     const string expected = "HELLOHELLO"; 
     const string dataToSend = "HELLO"; 

     // Start the server in a background task. 
     // We do this because the receive call is blocking. 
     var bgTask = Task.Factory.StartNew(() => 
     { 
      var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      try 
      { 
       // Bind to the endpoint and start listening. 
       server.Bind(endpoint); 
       server.Listen(10); // 10 is max allowed connections in queue (I think) 

       // Client connected, receive data 
       var connectingClient = server.Accept(); 

       // So low-level we even get to allocate room for the data buffer manually. 
       var buf = new byte[1024]; 

       // Hangs until data flows. 
       var sz = connectingClient.Receive(buf); // This is the size of the data we just received. 
       var data = Encoding.ASCII.GetString(buf, 0, sz); // We use the size to only grab what we need from the buffer. 
       Console.WriteLine("Data received: {0}", data); 

       // This is going to pass because we sent the data twice, 
       // and the call to Receive would not be able to complete in time 
       // for it to clear before more data becomes available. 
       Assert.Equal(expected, data); 

       /* 
       * BAM! Theory proven. We seriously had issues 
       * because we didn't understand how it worked. This is why you usually end 
       * your transmission with a newline. 
       */ 

       Console.WriteLine("Server closing"); 
       server.Close(); 
      } 
      catch (Exception e) 
      { 
       // Make sure we close the server. 
       server.Close(); 
       throw; 
      } 
     }); 

     // Create a client socket and connect it to the server. 
     // The server thread should have started it up by now. 
     var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     client.Connect(endpoint); 

     // Get the bytes of our string 
     var buffer = Encoding.ASCII.GetBytes(dataToSend); 

     // Send it out twice. This happens faster than the server will process it, 
     // so the data is stacking up. You would THINK that .Receive would 
     // simply return the first data sent to it, and the next time .Receive is called 
     // return the next. But that's not how it works, apparently. 
     client.Send(buffer); 
     client.Send(buffer); 

     // Wait for the server to finish whatever it's doing. 
     try 
     { 
      // We give it 3000ms to complete. 
      bgTask.Wait(); 
     } 
     catch (AggregateException ag) 
     { 
      // Throw any esceptions that were thrown in the background thread. 
      ag.Handle(ex => { throw ex; }); 
     } 

     // Close the client socket. 
     client.Close(); 
    } 
} 

我们通过用换行符分隔数据解决了这个问题。有趣的事实:我在搞TcpClient,发现如果我没有给流写一个换行符,它不会发送任何东西 - 它只会挂在那里。虽然可能是本地化的问题。任何人都在意详细说明这一点?