【问题标题】:C# Server - Socket not connecting and out of memory exceptionC# 服务器 - 套接字未连接和内存不足异常
【发布时间】:2015-03-03 15:51:56
【问题描述】:

我正在尝试实现一个简单的 TCP 服务器,我基本上复制了示例 on MSDN 没有几行,并试图使其工作。我有一个外部客户端已经在尝试连接。 这是我的代码:

IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
 IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0], 4001);

 Socket listener = new Socket(localEP.Address.AddressFamily,
     SocketType.Stream, ProtocolType.Tcp);

 try
 {
     listener.Bind(localEP);
     listener.Listen(1000);

    while (true)
     {

         listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
     }
 }
 catch (Exception e)
 {
   //Log here
 }

这是我的回调:

private void AcceptCnxCallback(IAsyncResult iar)
{

    MensajeRecibido msj = new MensajeRecibido();

    Socket server = (Socket)iar.AsyncState;
    msj.workSocket = server.EndAccept(iar);

}

这是其中一个传入包的信息:

TCP:[SynReTransmit #1727889]Flags=......S., SrcPort=57411, DstPort=4001, PayloadLen=0, Seq=673438964, Ack=0, Win=5840 ( Negotiating scale factor 0x4 ) = 5840  

来源:10.0.19.65 目的地:10.0.19.59

我基本上有两个问题:

  1. 如果我使用 while 循环,我会得到 OutOfMemoryException

  2. 我从来没有设法连接到客户端

关于这两个问题中的任何一个的任何提示?先感谢您!

【问题讨论】:

  • 对不起,我加了!但它甚至从未进入回调。谢谢!
  • 您似乎一直在调用 BeginAccept。如果你想在 while 内处理接受,你可能需要一个阻塞调用而不是异步调用。
  • 您从 MSDN 页面中遗漏的部分看起来是线程同步位,它可以防止无限的非阻塞循环。
  • 如果我试图接受多个连接,这样做是否明智?我将尝试弄清楚如何使线程同步位起作用,谢谢!
  • 糟糕的文章...请看这个关于如何构建异步TCP服务器和客户端的演示:github.com/vtortola/AynchronousTCPListener

标签: c# sockets server


【解决方案1】:

您的问题是,您一直在使用异步调用。没有等待机制或类似机制,因此通常您只是在无限循环中创建新的异步回调。

对于基本 TCP,我建议使用简单方法并使用同步方法。 Accept() 是阻塞的,所以程序流将停止,直到有传入连接。

while (true)
{
    Socket s = listener.Accept();

    buffer = new byte[BUFFER_SIZE];
    s.Receive(buffer);
    //Do something
    s.Send(...);

}

不,这只是一个基本示例。如果您想保持连接,您可以考虑为每个接受的 Socket 创建一个新线程,以继续接收和发送数据。

【讨论】:

    【解决方案2】:

    第一个问题 您正在使用无限循环来调用异步方法。

    试试这样:

    listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
    
    //add your code here (this part will be executed wile the listner is waiting for a connection.
    while (true)
         {
    
    
             Thread.Sleep(100);
    
         } 
    

    并将回调方法更改为:

    private void AcceptCnxCallback(IAsyncResult iar)
    {
    
        MensajeRecibido msj = new MensajeRecibido();
    
        Socket server = (Socket)iar.AsyncState;
        msj.workSocket = server.EndAccept(iar);
    
    //call again the listener after you get a message
    listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
    }
    

    【讨论】:

    • 轮询循环不是他无限循环的解决方案。
    • 当然,使用异步方法的目的是使线程不会被阻塞,这正是您使用 Thread.Sleep 所做的。
    • @Ceisc 您可以将 Thread.Sleep 替换为您的代码部分...我将编辑该部分。
    • while 循环的要点是,它在被告知正在处理初始 Accept 后再次开始等待连接。打破它并从处理程序中再次调用 BeginAccept 然后完全不需要 while 循环。
    • @usr 我没有说这是一个最佳解决方案,但它会解决他的内存不足问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多