我已经在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已建立的连接已被主机中的软件中止
答案 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)
这是一个样板错误消息,它来自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代码是循环的,所以我猜它是三个中的一个:
你的php代码应该是:
socket_recv()
处理 - 稍后再处理。)然后在循环内:
socket_accept()
)。如果你得到一个socket_read()
标题,请握手一次并记住数组中的套接字。socket_recv()
)读入缓冲区。
socket_recv()
为“false”(使用===进行比较)然后丢弃套接字,则断开连接。提示使用“非阻塞”模式,当您发送数据时,还会发送“End Of Command”字符。这有助于PHP知道它有完整的指令而不是一部分。
如果PHP是套接字服务器,只有socket_recv() === false
关闭套接字或者你要结束程序。否则他们会保持活跃并循环。
另一个指针是确保重新使用IP地址。 socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
(注意:如果PHP是套接字客户端,则适用不同的规则,这仅适用于您将PHP用作套接字服务器。)