我试图编写客户端 - 服务器通信代码。到目前为止,我设法在第一个线程中连接。第二个线程读取套接字,第三个线程检查客户端是否没有意外的disconection。
我的问题是,当我尝试读取套接字时,我收到了System.ObjectDisposedException。如果我继续运行程序(忽略异常),当我检查套接字是否仍然连接时,会发生同样的异常。
服务器是一个包含以下字段的类:
static class Server
{
static ArrayList readList = new ArrayList();
static ArrayList acceptList = new ArrayList();
static public Thread thread1 = new Thread(new ThreadStart(SocketConnector));
static Thread thread2 = new Thread(new ThreadStart(SocketListener));
static Thread thread3 = new Thread(new ThreadStart(SocketClose));
static Thread thread4 = new Thread(new ParameterizedThreadStart(SocketWriter));
readList用于套接字读取器线程(此消息中的最后一个代码示例) acceptList包含Socket.Accept()的结果。以下是acceptList的填充方式。
static void SocketConnector()
{
while (true)
{
sock.Listen(25);
actif = sock.Accept();
if (actif != null)
{
lock (acceptList)
{
acceptList.Add(actif);
Console.WriteLine("IT WORKS");
// that writeline appeared when i try to connect with the client.
}
actif = null;
}
}
现在我在这里检查是否有任何意外断开与客户端的连接:
static void SocketClose()
{
while (true)
{
for (int i = 0; i < acceptList.Count; ++i)
{
if (((Socket)acceptList[i]).Poll(25, SelectMode.SelectRead) && ((Socket)acceptList[i]).Available == 0)
{
lock (acceptList)
{
((Socket)acceptList[i]).Close();
Console.WriteLine("Client " + ((Socket)acceptList[i]).GetHashCode() + " déconnecté");
acceptList.Remove((Socket)acceptList[i]);
i--;
}
}
}
Thread.Sleep(5);
}
代码的最后一部分我需要显示我是如何阅读我的套接字的。
static void SocketListener()
{
while (true)
{
readList.Clear();
lock (acceptList)
{
for (int i = 0; i < acceptList.Count; i++)
{
readList.Add((Socket)acceptList[i]);
}
}
if (readList.Count > 0)
{
Socket.Select(readList, null, null, 1000);
for (int i = 0; i < readList.Count; i++)
{
if (((Socket)readList[i]).Available > 0)
{
while (((Socket)readList[i]).Available > 0)
{
Console.WriteLine("Debut Deserialisation");
// get the underlying socket for the TcpClient
TcpClient client = new TcpClient();
client.Client = (Socket)readList[i];
NetworkStream ns = client.GetStream();
BinaryReader reader = new BinaryReader(ns);
Message received = new Message();
Console.WriteLine(received.msg);
Console.WriteLine(received.user);
Console.WriteLine(received.targetChatroom);
// Deserialisation
int length = reader.ReadInt32();
byte[] msgArray = reader.ReadBytes(length);
received.msg = Encoding.UTF8.GetString(msgArray);
length = reader.ReadInt32();
msgArray = reader.ReadBytes(length);
received.user = Encoding.UTF8.GetString(msgArray);
length = reader.ReadInt32();
msgArray = reader.ReadBytes(length);
received.targetChatroom = Encoding.UTF8.GetString(msgArray);
ns.Close();
}
}
}
}
}
我意识到我的套接字可能被ns.Close()行关闭了,导致错误。使用ns.Close(),我只是尝试关闭我创建的流以从套接字获取数据,而不是关闭套接字本身。我试图删除那个ns.Close()行,并且ObjectDisposedException不再出现了!但是,现在我在行中得到了一个OutOfMemoryException:
byte[] msgArray = reader.ReadBytes(length);
在阅读帖子中。我认为这个异常是因为流没有关闭引起的。
编辑:OutOfMemoryException来自客户端中的代码。问题解决了。
断开检测工作,以及反序列化。
我的问题是:我应该何时关闭该流?
答案 0 :(得分:0)
使用Socket.Select
时,实际上不需要额外的线程 - 只需在checkError
参数和checkRead
参数中包含套接字。
它可能看起来像断开位工作,因为在测试期间它关闭了你的套接字,但我的猜测是远程连接实际上发送了一个有效的断开连接(而不是“意外”断开连接)消息,导致你的读取线程在现在关闭的插座上窒息。
您应该期望Socket
上的任何操作都会针对意外错误抛出SocketException
,和期望正常断开连接的消息正好为0字节。
我没有那么多使用BinaryReader
,但我希望它会在EndOfStreamException
处抛出int length = reader.ReadInt32();
。