下面是创建侦听Socket对象的方法代码。
Code
/// <summary> /// 创建接收服务器的 Socket, 并侦听客户端连接请求 /// </summary> private bool CreateReceiverSocket() { try { _receiverSocket =new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _receiverSocket.Bind(new IPEndPoint(IPAddress.Any, _tcpSocketPort));// 绑定端口 _receiverSocket.Listen(_maxAllowListenQueueLength);// 开始监听 return true; } catch { this.OnReceiverException(); return false; } } 3.2 侦听客户端连接请求 服务器端循环等待客户端连接请求。一旦有请求,先判断客户端连接数是否超限,接着检测该客户端IP地址,一切正常后建立TSession对象,并调用异步方法接收客户端Socket数据包。 代码中,Socket读到数据时的回调AsyncCallback委托方法EndReceiveData()完成数据接收工作,正常情况下启动另一个异步BeginReceive()调用。 .NET中,每个异步方法都有自己的独立线程,异步处理其实也基于多线程机制的。下面代码中的异步套异步调用,既占用较大的系统资源,也给处理带来意想不到的结果,更是出现异常时难以控制和处理的关键所在。
Code
/// <summary> /// 循环侦听客户端请求,由于要用线程池,故带一个参数 /// </summary> private void ListenClientRequest(object state) { Socket client =null; while (!_stopReceiver) { if (_stopConnectRequest)// 停止客户端连接请求 { if (_receiverSocket!= null) { try { _receiverSocket.Close(); // 强制关闭接收器 } catch { this.OnReceiverException(); } finally { // 必须为 null,否则 disposed 对象仍然存在,将引发下面的错误 _receiverSocket =null; } } continue; } else { if (_receiverSocket== null) { if (!this.CreateReceiverSocket()) { continue; } } } try { if (_receiverSocket.Poll(_loopWaitTime, SelectMode.SelectRead)) { // 频繁关闭、启动时,这里容易产生错误(提示套接字只能有一个) client = _receiverSocket.Accept(); if (client != null&& client.Connected) { if (this._clientCount>= this._maxAllowClientCount) { this.OnReceiverException(); try { client.Shutdown(SocketShutdown.Both); client.Close(); } catch { } } else if (CheckSameClientIP(client))// 已存在该 IP 地址 { try { client.Shutdown(SocketShutdown.Both); client.Close(); } catch { } } else { TSession session =new TSession(client); session.LoginTime = DateTime.Now; lock (_sessionTable) { int preSessionID= session.ID; while (true) { if (_sessionTable.ContainsKey(session.ID))// 有可能重复该编号 { session.ID =100000 + preSessionID; } else { break; } } _sessionTable.Add(session.ID, session); // 登记该会话客户端 Interlocked.Increment(ref _clientCount); } this.OnClientRequest(); try // 客户端连续连接或连接后立即断开,易在该处产生错误,系统忽略之 { // 开始接受来自该客户端的数据 session.ClientSocket.BeginReceive(session.ReceiveBuffer,0, session.ReceiveBufferLength, SocketFlags.None, EndReceiveData, session); } catch { session.DisconnectType = TDisconnectType.Exception; session.State = TSessionState.NoReply; } } } else if (client != null)// 非空,但没有连接(connected is false) { try { client.Shutdown(SocketShutdown.Both); client.Close(); } catch { } } } } catch { this.OnReceiverException(); if (client != null) { try { client.Shutdown(SocketShutdown.Both); client.Close(); } catch { } } } // 该处可以适当暂停若干毫秒 } // 该处可以适当暂停若干毫秒 } |