套接字连接问题

时间:2011-11-28 23:38:19

标签: c# memory garbage-collection


我的回答:

生气后,我找到了解决方案。问题确实是C#的C#垃圾收集器或C#的多线程,它可能认为该线程中不再需要该对象,并将其删除。解决方案如下:

我将ClientThread实现到Server类中,将Client对象作为参数传递,这个小改动使其工作。感谢您的所有回复,如果将来有人遇到此问题,可能不是C#的垃圾收集器。但C#mutithreading OR网络必须在同一个类中完成。我保留了我的客户端类,只是使线程对象在Server类中运行该函数。

如果有人能弄清楚我的问题是什么,请随意发表评论,以便扩展我对C#内存管理的一点知识。

再次感谢所有试图帮助我的人。


原始问题

我是一名C ++程序员,所以我习惯于自己管理内存,我真的不知道如何解决这个问题。

例如在C ++中:

while(true)
{
    void* ptr = new char[1000];
}

这将是一个明显的内存泄漏程序,因此我需要继续使用以下内容进行清理:

delete ptr;

但是有些情况下我想在不同的线程中创建内存并且我不想在循环之后删除它。

while(true)
{
    socket.Accept(new Client());
}
//////////Client Constructor////////////
Client()
{
    clientThread.Start();
}

这段代码基本上就是我想用C#做的,但是我的客户端连接然后立即断开连接,我假设这是因为在while循环结束时我的new Client()被删除了我们最喜欢的垃圾收集器。

所以我的问题是,如何解决这个问题并使其不删除我的对象。

许多人回答说在代码中有关于它的其他链接的各种事情。我忘了提到我还将新客户端保存在全球客户列表中

List<Client> clients;



//inside loop
clients.Add(new Client(socket.Accept()));

好的,因为我不确定我是否缺少更多信息,这里是ACTUAL代码段

// Server class
    internal Socket socket { get; set; }
    internal Thread thread { get; set; }
    internal List<Client> clients { get; set; }
    internal void Init()
    {
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        thread = new Thread(AcceptThread);
    }
    internal void Start(int port,List<Client> clients)
    {
        var ipep = new IPEndPoint(IPAddress.Any, port);
        this.socket.Bind(ipep);
        this.socket.Listen(10);
        this.clients = clients;

        this.thread.Start();
    }
    internal void End()
    {
        socket.Close();
        thread.Abort();
    }
    internal void AcceptThread()
    {
        int ids = 0;

        while (true)
        {
            Client client = new Client();
            client.Init(socket.Accept());
            client.clientid = ids++;
            client.Start();
            clients.Add(client);
        }
    }

// Client class
public class Client
{
    .....

    #region Base Code

    internal void Init(Socket socket)
    {
        this.socket = socket;
        this.status = new SocketStatus();
        this.thread = new Thread(ClientThread);
        this.stream = new Stream();
    }
    internal void Start()
    {
        thread.Start();
    }
    internal void Close()
    {
        socket.Close();
        status = SocketStatus.Null;
        thread.Abort();
    }
    internal void ClientThread()
    {
        try
        {
            while (true)
            {
                byte[] data = new byte[1];
                int rec = socket.Receive(data);
                if (rec == 0)
                    throw new Exception();
                else
                    stream.write(data[0]);
            }
        }
        catch(Exception e)
        {
            Close();
        }
    }
    #endregion
}

感谢您的所有回复。

4 个答案:

答案 0 :(得分:2)

这根本不是它的工作方式。如果您创建的Client实例存在任何引用,则不会对其进行垃圾回收。这不仅适用于您自己的代码。因此,如果GCing确实是您问题的根源,那么您永远无法在第一时间访问它!

如果您不打算访问它,无论如何都可以将它们放在List中。但是,我相信一旦你在你正在讨论的另一个线程中使用它们,你的问题就会消失。

答案 1 :(得分:1)

我已经离开了c#游戏一段时间,但我没有看到任何错误。在实际不再引用对象之前,垃圾收集不应该启动。如果您的socket.Accept()没有保留参考,也许您可​​以手动执行此操作:

var clients = new List<Client>();

while(true)
{
    client = new Client();
    clients.Add(client);
    socket.Accept(client);
}

////////// Client Constructor ////////////

Client()
{
    clientThread.Start();
}

答案 2 :(得分:1)

来自MSDN

  

如果没有可用于读取的数据,Receive方法将阻塞,直到数据为止   可用,除非使用设置了超时值   Socket.ReceiveTimeout。如果超出超时值,则接收   call会抛出一个SocketException。如果您处于非阻塞模式,   并且协议栈缓冲区中没有可用的数据,   Receive方法将立即完成并抛出一个   SocketException。您可以使用Available属性来确定是否   数据可供阅读。当Available为非零时,重试   接受手术。

     

如果您使用面向连接的Socket,Receive方法将会   读取尽可能多的数据,最大可达缓冲区的大小。如果   远程主机通过Shutdown关闭Socket连接   方法,并且已接收所有可用数据,即Receive方法   将立即完成并返回零字节。

这似乎是从Receive方法获取0返回值的唯一方法,并且 not 得到异常,因此看起来另一端的任何东西都是关闭连接。

答案 3 :(得分:0)

垃圾收集器仅删除程序中任何引用都无法访问的资源。只要你还有一个引用该对象的变量,它就会继续存在。