【发布时间】:2015-11-22 18:04:42
【问题描述】:
我正在尝试编写客户端-服务器通信。到目前为止,我设法在第一个线程中连接。第二个线程读取套接字,第三个线程检查是否没有来自客户端的意外断开连接。
我的问题是当我尝试读取套接字时出现 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 来自客户端中的代码。问题在这里解决了。
断线检测有效,反序列化也有效。
我的问题是:我应该什么时候关闭该流??
【问题讨论】:
-
很多代码但仍然不完整。目前还不清楚它在哪个线程上运行,
new Thread(new ThreadStart(SocketClose));看起来不是一个很棒的工具。您的阅读线程应该配合停止和关闭。 -
@Henk Holterman 你是对的。我编辑显示哪个代码示例属于哪个线程。 “SocketClose”线程是一个线程,如果其他主机在断开连接时没有向您发送数据包(例如,因为它不正常地断开连接),则检查套接字是否仍然连接。可能这个名字选得不太好。
标签: c# multithreading sockets out-of-memory objectdisposedexception