Java &引用;现有连接被远程主机强制关闭;接收时在UDP服务器中
因此,在与线程斗争之后,我成功地在客户机和服务器之间建立了一个流。我的客户端是一个Java Android Studio应用程序,服务器是一个C#控制台 我希望能够启动流并在客户端单击按钮时停止它。然后随时重新启动,停止,重新启动,停止。。等等 我很喜欢start,但有时在第一次停止后,有时在第一次重新启动时,有时在第二次重新启动时,会弹出Java &引用;现有连接被远程主机强制关闭;接收时在UDP服务器中,java,c#,android,udp,datagram,Java,C#,Android,Udp,Datagram,因此,在与线程斗争之后,我成功地在客户机和服务器之间建立了一个流。我的客户端是一个Java Android Studio应用程序,服务器是一个C#控制台 我希望能够启动流并在客户端单击按钮时停止它。然后随时重新启动,停止,重新启动,停止。。等等 我很喜欢start,但有时在第一次停止后,有时在第一次重新启动时,有时在第二次重新启动时,会弹出一个现有连接被远程主机强制关闭 在PacketReceived=serverSocket.Receive(ref-client)上 我不知道为什么,我正在努力
一个现有连接被远程主机强制关闭
在PacketReceived=serverSocket.Receive(ref-client)上代码>
我不知道为什么,我正在努力调试它,但没有效率。我的逻辑或语法有什么问题
C#服务器代码:
class UdpServer
{
static void Main(string[] args)
{
// variables declaration block
byte[] PacketReceived = new byte[1024];
var MyToken = new CancellationTokenSource(); //create token for the thread cancel
UdpClient serverSocket = new UdpClient(15000);
string PacketMessage = "";
int i = 0;
while (true) // this while for keeping the server "listening"
{
Console.WriteLine("Waiting for a UDP client..."); // display stuff
IPEndPoint client = new IPEndPoint(IPAddress.Any, 0); // prepare
PacketReceived = serverSocket.Receive(ref client); // receive packet
PacketMessage = Encoding.ASCII.GetString(PacketReceived, 0, PacketReceived.Length); // get string from packet
Console.WriteLine("Response from " + client.Address); // display stuff
Console.WriteLine("Message " + i++ + ": " + PacketMessage + "\n"); // display received string
if (PacketMessage == "Start")
{
MyToken = new CancellationTokenSource(); // for the restart, need a new token
Task.Run(() => Start(ref serverSocket, ref client), MyToken.Token); //start method on another thread
}
if (PacketMessage == "Stop")
{
MyToken.Cancel();
}
}
}
static public void Start(ref UdpClient serverSocket, ref IPEndPoint client)
{
int i = 0;
byte[] dataToSend;
while (true)
{
try
{
dataToSend = Encoding.ASCII.GetBytes(i.ToString());
serverSocket.Send(dataToSend, dataToSend.Length, client);
i++;
}
catch (Exception e)
{ }
}
}
}
Java客户端代码:
public class MainActivity extends AppCompatActivity {
String message;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button StrtBtn = (Button) findViewById(R.id.StartButton);
Button StpBtn = (Button) findViewById(R.id.StopButton);
// Start Button Click
StrtBtn.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
message = "Start";
SendUdpMsg();
}
}
);
// Stop Button Click
StpBtn.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
message = "Stop";
}
}
);
}
public void SendUdpMsg()
{
Thread networkThread = new Thread() {
// No local Host 127.0.0.1 in Android
String host = "192.168.200.3"; // Server's IP
int port = 15000;
DatagramSocket dsocket = null;
public void run() {
try {
// Get the Internet address of the specified host
InetAddress address = InetAddress.getByName(host);
// wrap a packet
DatagramPacket packetToSend = new DatagramPacket(
message.getBytes(),
message.length(),
address, port);
// Create a datagram socket, send the packet through it.
dsocket = new DatagramSocket();
dsocket.send(packetToSend);
// Here, I am receiving the response
byte[] buffer = new byte[65535]; // prepare
DatagramPacket packetReceived = new DatagramPacket(buffer, buffer.length); // prepare
while (true)
{
if(message == "Start")
{
dsocket.receive(packetReceived); // receive packet
byte[] buff = packetReceived.getData(); // convert packet to byte[]
final String Response = new String(buffer, 0, packetReceived.getLength());
runOnUiThread(new Runnable()
{
@Override
public void run()
{
// this is executed on the main (UI) thread
final TextView TextOne = (TextView)findViewById(R.id.StatusText);
TextOne.setText(Response);
}
});
}
else
{
// wrap a packet to send the Stop
packetToSend = new DatagramPacket(
message.getBytes(),
message.length(),
address, port);
// Create a datagram socket, send the packet through it.
dsocket = new DatagramSocket();
dsocket.send(packetToSend);
break; // break the whole thread
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
networkThread.start();
}
}
如果没有完整的代码示例(特别是要测试的真实客户端),很难诊断这样的错误。但是,您的代码中至少有两个明显的问题,如果出现错误,这两个问题中的任何一个都可能导致类似的错误:
您通过引用Start()
方法传递serverSocket
和client
。不需要这样做,通过引用传递客户端
会引入在错误时间修改客户端
变量的可能性,导致尝试发送到任何
,或导致非法引用(如果在x64体系结构上运行)。这是最基本的问题,即在没有某种同步的情况下在线程之间共享变量(至少使用volatile
)会带来它自己的问题集合(并且在客户端代码中存在相同的线程安全问题,因为使用message
字段作为线程之间的信号的方式)
您从未使用取消令牌停止线程。将令牌传递给Task.Run()
方法只允许Task
类正确处理可能发生的任何取消异常。但是,在适当的时候抛出该异常取决于您自己的代码。您永远不会这样做,这意味着在从客户端发送多条消息之后,您将遇到多个线程试图发送到客户端
我赌的是上面的第二个。您的客户端似乎将端口选择权留给主机,因此每次发送“Start”方法时,客户端端口都可能发生更改。关闭以前使用的套接字后,该端口无效,如果远程套接字尝试发送到该端口,则会导致远程套接字出错。当然,您的服务器(远程套接字)将尝试发送到该端口,从而在套接字上导致错误,该错误可由Receive()
方法引发(而不是您可能期望的send()
方法)
顺便说一句,无论如何,您应该避免将线程池用于长时间运行的任务。至少,如果要使用Task.Run()
启动线程,请通过传递适当的值向.NET指示任务是长期运行的: