等待传入 tcp/ip 服务器请求
Wait for incoming tcp/ip server request
我正在为我的应用程序与仓库系统建立一个 TCP/IP 连接。交流是这样的。
- 我向仓库系统的TCP/IP(Socket)服务器发送消息
- 仓库系统向我的本地 TCP/IP 服务器响应一条消息。
因此没有直接回复消息。相反,每个应用程序都是自己的服务器。
但是我希望我的应用程序等待来自其他服务器的响应。
基本上我有以下代码。
public string ControllerFunction() {
startLocalTcpIpServer();
sendMessage("a message");
return clientMessage;
}
这是我自己用 start() 函数启动的服务器
public void Start() {
// Start TcpServer background thread
tcpListenerThread = new Thread(new ThreadStart(ListenForIncommingRequests)) {
IsBackground = true
};
tcpListenerThread.Start();
}
private void ListenForIncommingRequests() {
try {
tcpListener = new TcpListener(IPAddress.Parse(serverIp), port);
tcpListener.Start();
byte[] bytes = new byte[1024];
Console.WriteLine("Server Started");
while(true) {
// Get a stream object for reading
using(NetworkStream stream = tcpListener.AcceptTcpClient().GetStream()) {
int length;
// Read incomming stream into byte arrary.
while((length = stream.Read(bytes, 0, bytes.Length)) != 0) {
byte[] incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
// Convert byte array to string message.
string clientMessage = Encoding.ASCII.GetString(incommingData);
}
}
}
}
catch(SocketException socketException) {
Console.WriteLine("SocketException " + socketException.ToString());
}
}
所以我想再次使用结果字符串 clientMessage
作为我的 ControllerFunction 的 return。但是如何以正确的方式获取数据?
所以你需要的是能够等待来自应用程序中另一个地方(本地服务器)的响应。响应将首先在那里被解雇。本地服务器应该有一个您可以订阅的事件(在我的示例中为 OnMessage
)。此活动会将结果消息转发给您。
可以使用 TaskCompletionSource 处理同步。您将创建可用于同步或异步获取结果的任务。
像这样:
public string ControllerFunction()
{
return ControllerFunctionTask().Result;
}
public Task<string> ControllerFunctionTask()
{
sendMessage("a message");
var task = new TaskCompletionSource<string>();
localServer.OnMessage = (message) =>
{
task.SetResult(message);
};
return task.Task;
}
如评论所述,同步等待异步Task可能会导致死锁。当调用者线程是 context
线程(UI、ASP)时,可能会发生这种情况。因此这应该是更好的方法:
public async Task<string> ControllerFunction()
{
return await ControllerFunctionTask();
}
public Task<string> ControllerFunctionTask()
{
sendMessage("a message");
var task = new TaskCompletionSource<string>();
localServer.OnMessage = (message) =>
{
task.SetResult(message);
};
return task.Task;
}
OnMessage
可以这样定义:
public event Action<string> OnMessage;
然后它将在您获得 clientMessage 字符串的行之后立即调用:
string clientMessage = Encoding.ASCII.GetString(incommingData);
if (OnMessage != null)
OnMessage(clientMessage);
我正在为我的应用程序与仓库系统建立一个 TCP/IP 连接。交流是这样的。
- 我向仓库系统的TCP/IP(Socket)服务器发送消息
- 仓库系统向我的本地 TCP/IP 服务器响应一条消息。
因此没有直接回复消息。相反,每个应用程序都是自己的服务器。 但是我希望我的应用程序等待来自其他服务器的响应。
基本上我有以下代码。
public string ControllerFunction() {
startLocalTcpIpServer();
sendMessage("a message");
return clientMessage;
}
这是我自己用 start() 函数启动的服务器
public void Start() {
// Start TcpServer background thread
tcpListenerThread = new Thread(new ThreadStart(ListenForIncommingRequests)) {
IsBackground = true
};
tcpListenerThread.Start();
}
private void ListenForIncommingRequests() {
try {
tcpListener = new TcpListener(IPAddress.Parse(serverIp), port);
tcpListener.Start();
byte[] bytes = new byte[1024];
Console.WriteLine("Server Started");
while(true) {
// Get a stream object for reading
using(NetworkStream stream = tcpListener.AcceptTcpClient().GetStream()) {
int length;
// Read incomming stream into byte arrary.
while((length = stream.Read(bytes, 0, bytes.Length)) != 0) {
byte[] incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
// Convert byte array to string message.
string clientMessage = Encoding.ASCII.GetString(incommingData);
}
}
}
}
catch(SocketException socketException) {
Console.WriteLine("SocketException " + socketException.ToString());
}
}
所以我想再次使用结果字符串 clientMessage
作为我的 ControllerFunction 的 return。但是如何以正确的方式获取数据?
所以你需要的是能够等待来自应用程序中另一个地方(本地服务器)的响应。响应将首先在那里被解雇。本地服务器应该有一个您可以订阅的事件(在我的示例中为 OnMessage
)。此活动会将结果消息转发给您。
可以使用 TaskCompletionSource 处理同步。您将创建可用于同步或异步获取结果的任务。
像这样:
public string ControllerFunction()
{
return ControllerFunctionTask().Result;
}
public Task<string> ControllerFunctionTask()
{
sendMessage("a message");
var task = new TaskCompletionSource<string>();
localServer.OnMessage = (message) =>
{
task.SetResult(message);
};
return task.Task;
}
如评论所述,同步等待异步Task可能会导致死锁。当调用者线程是 context
线程(UI、ASP)时,可能会发生这种情况。因此这应该是更好的方法:
public async Task<string> ControllerFunction()
{
return await ControllerFunctionTask();
}
public Task<string> ControllerFunctionTask()
{
sendMessage("a message");
var task = new TaskCompletionSource<string>();
localServer.OnMessage = (message) =>
{
task.SetResult(message);
};
return task.Task;
}
OnMessage
可以这样定义:
public event Action<string> OnMessage;
然后它将在您获得 clientMessage 字符串的行之后立即调用:
string clientMessage = Encoding.ASCII.GetString(incommingData);
if (OnMessage != null)
OnMessage(clientMessage);