我正在尝试使用.net套接字构建自己的异步客户端/服务器应用。
使用这两个示例,基本功能起作用。
此示例在连接后向服务器发送一个字符串,服务器回复并回显它收到的字符串,然后返回给客户端。
此回复后,客户端将关闭。
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
在我的场景中,我尝试连接到服务器,然后通过用户输入从客户端将数据发送到服务器。我回覆<OK>
。
在上面链接的此示例中,客户端在发送后始终等待回调(因此,我的回复<OK>
)。
我没有像示例中那样关闭客户端,因为我想按需发送连续的字符串。我需要服务器继续侦听和回复以确认收到字符串。
我很确定我对应该发生和不应该发生的事情缺少一些核心了解。
现在,我可以发送一个字符串,服务器会回复,客户端会收到此<ok>
。然后,我尝试发送另一个字符串,但是服务器从不“接收”该字符串。我猜服务器现在在发送字符串后也正在等待回调,但是如果我在接收到客户端之后将某些东西返回给服务器,那么整个循环会继续并重复吗?
在回复“确定”后,如何使服务器等待更多“新”数据?
我是否必须告诉它再次“收听”任何新数据?好像是重新启动连接,这不是我的意图...
我希望能对我在这里缺少的东西有所了解...
(PS服务器在发送时连接了回调事件。我这样保留它,因为这是我链接,实现的代码示例。我是否必须更改服务器的发送例程?(不等待回调)?
我的服务器代码:
public static void StartListening()
{
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[1];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
xServerLog.AddLine("Server started: Listening on: " + localEndPoint.Address.ToString());
xServerLog.ipAddress = localEndPoint.Address.ToString();
xServerLog.port = port;
// Create a TCP/IP socket.
Socket myTCPserver = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
myTCPserver.Bind(localEndPoint);
myTCPserver.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
xServerLog.AddLine("Waiting for connections...");
myTCPserver.BeginAccept(
new AsyncCallback(AcceptCallback),
myTCPserver);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
xServerLog.AddLine("I think things are done here...");
// Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
// All the data has been read from the
// client. Display it on the console.
// Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
// content.Length, content);
xServerLog.AddLine("RX:" + content);
// Echo the data back to the client.
Send(handler, "<OK>");
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
//Console.WriteLine("Sent {0} bytes to client.", bytesSent);
xServerLog.AddLine("TX:OK"); // + bytesSent.ToString() + " bytes to client");
// handler.Shutdown(SocketShutdown.Both);
// handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public void Start()
{
StartListening();
// return 0;
}
我的客户代码:
class xtcpClient
{
// State object for receiving data from remote device.
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousClient
{
//remote ip port
// private static string remoteServerIP = "0.0.0.1";
private static IPAddress rIP;// = IPAddress.Parse(remoteServerIP);
private static IPEndPoint remoteEP; // = new IPEndPoint(rIP, port);
// Create a TCP/IP socket.
private static Socket myTCPClient; // = new Socket(rIP.AddressFamily,SocketType.Stream, ProtocolType.Tcp);
// The port number for the remote device.
private static int port; // = 11000;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
// private static String response = String.Empty;
private static string serverResponse = string.Empty;
private static void _open_client()
{
remoteEP = new IPEndPoint(rIP, port);
myTCPClient = new Socket(rIP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
myTCPClient.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), myTCPClient);
connectDone.WaitOne();
}
//////////private static void StartClient(IPAddress remoteIP, int remotePort)
//////////{
////////// // Connect to a remote device.
////////// try
////////// {
////////// _open_client();
////////// //rIP = remoteIP;
////////// //port = remotePort;
////////// // Establish the remote endpoint for the socket.
////////// // The name of the
////////// // remote device is "host.contoso.com".
////////// //IPHostEntry ipHostInfo = Dns.GetHostEntry("host.contoso.com");
////////// //IPAddress ipAddress = ipHostInfo.AddressList[1];
////////// // Send test data to the remote device.
////////// // string sendReply = "";
////////// // sendReply = Send(myTCPClient, "echo 123<EOF>"); //send an initial test echo
////////// // xClientLog.AddLine("Sent: Echo<EOF>");
////////// // xClientLog.AddLine("Server Replied: " + sendReply);
////////// // Write the response to the console.
////////// // Console.WriteLine("Response received : {0}", response);
////////// // xClientLog.AddLine("Response received: " + response);
////////// }
////////// catch (Exception e)
////////// {
////////// Console.WriteLine(e.ToString());
////////// }
//////////}
public void _close_connection()
{
// Release the socket.
myTCPClient.Shutdown(SocketShutdown.Both);
myTCPClient.Close();
}
private static string Send(Socket client, String data)
{
if (client is null)
{
_open_client();
}
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client); //fire sendcallback when done sending...
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(myTCPClient);
receiveDone.WaitOne();
return serverResponse; //return server response
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
xClientLog.AddLine("Sent bytes to server: " + bytesSent);
// Signal that all bytes have been sent.
sendDone.Set(); //signal the send event to finish, it will start listening for a reply...
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
xClientLog.AddLine("Socket connected to: " + client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state); //fire receivcallback event when done receining
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
serverResponse = state.sb.ToString();
if (serverResponse.IndexOf("<OK>") > -1) {
// All the data has been read from the server
xClientLog.AddLine("RX:" + serverResponse);
receiveDone.Set();
}
else
{
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
//public static int Main(String[] args)
//{
// StartClient();
// return 0;
//}
public void startClient(string remoteIP, int remotePort)
{
try
{
rIP = IPAddress.Parse(remoteIP);
port = remotePort;
_open_client();
}
catch (Exception e)
{
System.Windows.MessageBox.Show(e.Message + Environment.NewLine + e.InnerException.Message);
}
}
public string sendData(string DataToSend)
{
return (Send(myTCPClient, DataToSend));
}
}
}
答案 0 :(得分:0)
可能是因为服务器上的每个“接受呼叫”都接受一个新客户端。如果您想无限期地接受,您可以尝试这样的方法,以确保新客户始终有一个“接受接受”的电话:
while (true) {
var clientSocket = listeningSocket.Accept();
Task.Factory.StartNew(() => HandleClient(clientSocket));
}
客户端也有可能关闭连接。如果服务器使用Shutdown方法关闭Socket连接,并且已收到所有可用数据,则Receive方法将完成并且不返回任何内容。