从客户端(C#到PHP)的第二次调用时关闭套接字连接

时间:2014-08-05 04:53:20

标签: c# php sockets

我已经在C#中编写了一个客户端,在本地主机上编写了一个PHP服务器,并且应该通过套接字传递数据。

我使用以下C#代码从PHP服务器读取:

string getResponse(string request)
{
    string response = "";

    byte[] bytes = new byte[10024];

    byte[] msg = Encoding.ASCII.GetBytes(request);
    // Send the data through the socket.
    int bytesSent = Sender.Send(msg);


    // Receive the response from the remote device.
    int bytesRec = Sender.Receive(bytes);
    response = Encoding.ASCII.GetString(bytes, 0, bytesRec);


    return response;
}

和发件人,定义和发起如下

Socket Sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");               
IPEndPoint remoteEP = new IPEndPoint(ipAddress,8888);           
Sender.Connect(remoteEP);

代码在getResponse的第一次调用中正常工作,但在第二次调用中,它会生成以下错误 Sender.Receive致电:

  

未处理SocketException已建立的连接已被主机中的软件中止

6 个答案:

答案 0 :(得分:1)

我注意到在PHP 5中,我们可以使用stream_sockets 当我使用stream_socket而不是socket_create时,它就像一个魅力.... 这很奇怪,这是怎么回事?!有什么区别?

<?php
    # server.php

    $server = stream_socket_server("tcp://127.0.0.1:1337", $errno, $errorMessage);

    if ($server === false) {
        throw new UnexpectedValueException("Could not bind to socket: $errorMessage");
    }
    for (;;) {
        $client = @stream_socket_accept($server);

    if ($client) {
        stream_copy_to_stream($client, $client);
        fclose($client);
    }
}

答案 1 :(得分:0)

有时您必须多次接收单次发送。

尝试接收:

_socket.Receive(Buffer, 0, Buffer.Length, SocketFlags.None);

while (_socket.Available != 0)
{
   _socket.Receive(Buffer, readByte, Buffer.Length - readByte, SocketFlags.None);

}

答案 2 :(得分:0)

对于您的C#客户端,使用System.Net.WebClient类而不是较低级别的Socket类可能会更好。例如,WebClient.DownloadString方法几乎完成了代码尝试的操作,并且已经过全面测试。

答案 3 :(得分:0)

来自this question

  

这是一个样板错误消息,它来自Windows。底层错误代码是WSAECONNABORTED。这真的并不意味着超过&#34;连接被中止&#34;。你必须要小心一下你的主机&#34;这句话的一部分。在绝大多数Windows应用程序中,确实是桌面应用程序所连接的主机中断了连接。通常是其他地方的服务器。

     

但是,当您实现自己的服务器时,角色会颠倒过来。现在,您需要将错误消息读取为&#34;由应用程序在另一个电线&#34;中止。当您实现服务器时,这当然并不罕见,使用您的服务器的客户端程序不会因任何原因中止连接。这可能意味着防火墙或代理终止了连接,但这种情况不太可能,因为它们通常不允许首先建立连接。

在我看来,正在发生的事情是客户端(C#)正在尝试连接到服务器(PHP)。客户端发送请求,然后从PHP接收响应;然后,在第二次尝试通过同一套接字发送请求时,尝试再次发送/接收数据。

请记住,PHP是一种装饰HTTP协议的语言处理器,因此它基本上解释了PHP代码,然后通过HTTP层(Apache?)将普通的HTTP返回给请求者。

我不是HTTP方面的专家,而且远非PHP上的知识,但我认为这种情况正在发生,因为PHP正在接收您的数据,发送您的响应然后关闭连接。这是有道理的,因为通常我们不会在HTTP中保持套接字打开 - 我们只需触发请求,得到响应即可。

您正在做的事情是称为长轮询,这是HTTP连接的套接字保持打开更长时间的位置,以便服务器可以继续向客户端发送数据。我对这个主题不是很了解,但我的Google-Fu引导我SignalR,这可能会指出你正确的方向。

如果您没有寻找长轮询(即,您对创建长时间保持打开的套接字感兴趣),您只需重新连接您的写入服务器的套接字,如果它尚未打开。

这当然可能是完全错误的。但基于现象以及我对HTTP的了解似乎有道理。

TLDR:您正在尝试写入已经关闭的连接,因为HTTP(以及PHP)只需要每个响应一个请求。您需要重新连接到服务器的连接,或者您也可以实现长轮询。

答案 4 :(得分:0)

看起来你只是在修改套接字和连接一次。我不太确定,但我认为当网络响应结束时,它将关闭连接。所以这意味着你的第二次读取尝试将失败。您可以尝试将套接字连接代码放在get响应方法中。所以每次想要回复时都要建立连接。

答案 5 :(得分:0)

问题在于您的PHP代码,而不是您发布的c#。出于某种原因,它正在关闭连接,或者它认为存在错误,因此正在中止。

你已经说过PHP代码是循环的,所以我猜它是三个中的一个:

  1. 你正在重新协商每个循环的标题;你只需要协商每个新连接的标题;一旦连接,你只需阅读数据
  2. 你一直关闭套接字
  3. 你有阻塞模式的套接字(用PHP)。
  4. 你的php代码应该是:

    1. 打开套接字服务器,进入侦听模式。 (也应该是非阻塞的。通过socket_recv()处理 - 稍后再处理。)
    2. 无限循环
    3. 使用命令行,按Ctrl-C / Cmd-C中断。
    4. 然后在循环内:

      1. 寻找新的套接字连接(socket_accept())。如果你得到一个socket_read()标题,请握手一次并记住数组中的套接字。
      2. 然后运行在步骤1中存储的所有打开的套接字,并将(socket_recv())读入缓冲区。
        • 如果socket_recv()为“false”(使用===进行比较)然后丢弃套接字,则断开连接。
        • 如果socket有数据,则需要取消屏蔽并处理。
      3. 重复
      4. 提示使用“非阻塞”模式,当您发送数据时,还会发送“End Of Command”字符。这有助于PHP知道它有完整的指令而不是一部分。

        如果PHP是套接字服务器,只有socket_recv() === false关闭套接字或者你要结束程序。否则他们会保持活跃并循环。

        另一个指针是确保重新使用IP地址。 socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

        (注意:如果PHP是套接字客户端,则适用不同的规则,这仅适用于您将PHP用作套接字服务器。)