我正在建立一个TCP服务器/客户端通信,由于某种原因,只有当服务器接受,然后客户端尝试连接时,它才能正常工作。如果我在服务器接受之前启动客户端,它不会做任何事情。
服务器不是异步的(clientHandle = serverHandle.Accept()
),也许这就是问题所在,客户端是(s_ClientHandle.BeginnConnect(ipEndpoint, new AsyncCallback(ConnectCallback), s_ClientHandle)
)。服务器没有计划取回的数据,它只是打算将数据发送到客户端。
服务器:我有一个Windows窗体,使用一个单例类调用StartServer()
,这里的服务器类是一个简化的版本:
我知道这是一个很大的代码,客户端不包括在内。服务器代码只包括在内,因为它可能更好地理解我的问题
如果我使用一个异步服务器(写在下面),它连接得很好,就像它应该的那样,但是它从来没有发送过数据,因为服务器总是在监听(StartServer()
中的while(true)
)。有没有办法添加一个安全线程?或者其他什么?这样它就可以在不断监听的同时发送数据?或者Accept
和BeginAccept
之间有什么我不知道的规则?
namespace Server
{
public partial class NewForm : Form
{
string version = "null";
public NewForm()
{
InitializeComponent();
}
private void btnTState_Click(object sender, EventArgs e)
{
Singleton Single = Singleton.GetInstance();
Single.SendMsg(txtMsg.text);
}
}
}
单例类:
namespace Server{
public sealed class Singleton
{
private static Singleton instance = null;
public static Singleton GetInstance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
private Singleton()
{
Server.StartServer();
}
public void SendState(string msg)
{
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte[] data = new byte[4];
Array.Copy(enc.GetBytes(msg), 0, data, 0, 4);
Server.SendToClients(data);
}
}
}
伺服器
namespace Server
{
internal class Server
{
private static Socket serverHandle;
private static Socket clientHandle = null;
private static ArrayList clientList = new ArrayList();
public static void StartServer()
{
IPEndPoint ipep = null;
ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 59999);
// Create a TCP/IP socket.
serverHandle = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverHandle.Bind(ipep);
serverHandle.Listen(20);
clientHandle = serverHandle.Accept();
clientList.Add(clientHandle);
}
public static void SendToClients(byte[] data)
{
ArrayList clients = GetClients();
foreach (Socket client in clients)
{
client.Send(data, 0, data.Length, 0);
}
}
private static ArrayList GetClients()
{
ArrayList returnValue = new ArrayList();
lock (clientList)
{
foreach (Socket client in clientList)
{
returnValue.Add(client);
}
}
return returnValue;
}
}
}
异步:
public static void StartServer()
{
IPEndPoint ipep = null;
try
{
ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 59999);
serverHandle = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverHandle.Bind(ipep);
serverHandle.Listen(61);
while (true)
{
allEventsDone.Reset();
serverHandle.BeginAccept(new AsyncCallback(AcceptCallback), serverHandle);
allEventsDone.WaitOne();
}
}
catch (SocketException e)
{
}
catch (Exception e)
{ }
}
private static void AcceptCallback(IAsyncResult ar)
{
try
{
Socket server = (Socket)ar.AsyncState;
Socket clientHandle = server.EndAccept(ar);
allEventsDone.Set();
Read(clientHandle); // reads data, calls readcallback etc
lock (clientList)
{
clientList.Add(client);
}
catch (Exception e)
{
}
}
客户端是异步的(但它确实工作)
1条答案
按热度按时间1aaf6o9v1#
仅当服务器正在侦听时,连接才起作用。
如果要处理多个连接,使用
async
和Tasks会更容易,而且无论如何都应该将代码转换为这种更现代的样式。CancellationTokenSource
创建的CancellationToken
,然后可以通过取消它来关闭服务器。Socket
,只使用TcpListener
。127.0.0.1
,只使用IPAddress.Any
。ArrayList
已过时,您应该改用List<T>
。在这种情况下,您需要使用ConcurrentBag<T>
而不是手动锁定。您可以使用
CancellationToken
来调用此函数,如下所示