挂起Socket.Receive也不例外

时间:2012-03-29 03:16:38

标签: c# sockets udp plc fins

我有WPF C#应用程序,它使用FINS命令/帧通过以太网(UDP数据包)与PLC通信(即写入/读取欧姆龙PLC的内存地址)。

我可以成功向 WRITE PLC地址发送命令,但在 READ 命令期间尝试从PLC接收响应时,应用程序会挂起/崩溃。

要从PC发送到PLC的FINS数据包帧:

// Packets send to PLC to read Memory Address DM1000
byte[] sendPacket = new byte[]
{
    // 81 00 02 00 00 00 00 FF 00 19 01 01 82 00 64 00 00 01

    // FINS header
    0x81, //0.(ICF) Display frame information: 1000 0001 (Response required)
    0x00, //1.(RSV) Reserved by system: (hex)00
    0x02, //2.(GCT) Permissible number of gateways: (hex)02
    0x00, //3.(DNA) Destination network address: (hex)00, local network
    0x00, //4.(DA1) Destination node address: (hex)00, local PLC unit
    0x00, //5.(DA2) Destination unit address: (hex)00, PLC
    0x00, //6.(SNA) Source network address: (hex)00, local network
    0xFE, //7.(SA1) Source node address: (hex)05, PC's IP is 100.0.0.254
    0x00, //8.(SA2) Source unit address: (hex)00, PC only has one ethernet
    0x19, //9.(SID) Service ID: just give a random number 19

    // FINS command
    0x01, //10.(MRC) Main request code: 01, memory area read
    0x01, //11.(SRC) Sub-request code: 01, memory area read

    // Memory Area
    0x82, //12.Memory area code (1 byte): 82(DM)

    // Address information
    0x00, //13.Read start address (2 bytes): D100
    0x64, 
    0x00, //15.Bit address (1 byte): Default 0

    // Words read
    0x00, //16. Words read (2bytes)
    0x01
};

以下代码是我的Socket发送和接收:

sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.Connect(SERV_IP_ADDR, FINS_UDP_PORT);
sock.Send(sendPacket, 0, sendPacket.Length, SocketFlags.None);

int totalBytesRcvd = 0;     // Total bytes received so far
int bytesRcvd = 0;          // Bytes received in last read
while (totalBytesRcvd < sendPacket.Length)
{
    bytesRcvd = sock.Receive(sendPacket, totalBytesRcvd, sendPacket.Length - totalBytesRcvd, SocketFlags.None);
    if (bytesRcvd == 0)
    {
        MessageBox.Show("Connection closed prematurely.");
        break;
    }

    totalBytesRcvd += bytesRcvd;
}

我还尝试使用 Try-Catch ,但在应用程序挂起期间没有捕获异常。我检查了 eventvwr ,其中说:

Souce: Application Hangs - "...stopped interacting with Windows and was closed"详情(screenshot below)

enter image description here

2 个答案:

答案 0 :(得分:4)

您的应用程序挂起的原因显然是因为您的应用程序正在等待从源获取数据。在后台线程上安排长时间运行的IO或使用发送和接收的异步版本是一种很好的做法。您的代码包含以下行中的错误:

while (totalBytesRcvd < msg.Length) 
{ 
    // Application hangs right at the sock.Receive 
    sock.Receive(msg, totalBytesRcvd, msg.Length - totalBytesRcvd, SocketFlags.None); 

    totalBytesRcvd += bytesRcvd; 
} 

您正在等待totalBytesRcvd包含预期字节数,并且您通过添加bytesRcvd数据来更新它。但你永远不会更新bytesRcvd。你需要在bytesRcvd中捕获对sock.Receive的调用的返回值。如果这不能解决问题,那就意味着服务器和客户端之间存在通信问题(请注意,您使用的UDP可能不合理) - 或者实际消息的长度短于预期

答案 1 :(得分:0)

我遇到了同样的问题,发现我的解决方案是在尝试接收之前检查socket.Available。

byte[] bytes = new byte[tcpClient.ReceiveBufferSize];

if (socket.Available > 0)
{
   int bytesRec = socket.Receive(bytes);
   Console.WriteLine("Echoed test = {0}", Encoding.ASCII.GetString(bytes, 0, bytesRec));
}