应用TcpListener实现的socket服务器端详解编程语言

前言

项目中要实现一个简单的socket服务器端,采用了TcpListener这个类。除了基本的功能之外,有几处需要注意的点。

  1. 要能同时接收多个客户端的连接,当然,不需要几千个那么多。
  2. 要能探测到客户端的断开。
  3. 要能关闭服务器端的监听。

这几个点之间,2和3我没有找到很好的方法,是通过捕获异常的方法解决的。

重点功能

要能同时接收多个客户端的连接

MSDN上面的代码例子是连接一个客户端的情况,我需要可以连接多个客户端,采用了多线程的方式,即连接一个客户端之后,把处理客户端消息的部分用一个线程处理,这样可以继续新的监听,核心代码如下:

 private void ThreadListen() 
        { 
            while (this.StatusOn) 
            { 
                try 
                { 
                    TcpClient client = this.serverListener.AcceptTcpClient(); 
                    this.clientList.Add(client); 
                    this.ShowMsg(string.Format("客户端连接成功! ip = {0} port = {1}", ((IPEndPoint)client.Client.RemoteEndPoint).Address, ((IPEndPoint)client.Client.RemoteEndPoint).Port)); 
                    Thread t1 = new Thread(() => ThreadHandleMsg(client)); 
                    t1.Start(); 
                } 
                catch (Exception ex) 
                { 
                    Log.Error("", ex); 
                } 
            } 
        } 

要能探测到客户端的断开

在如下代码之处,while循环的条件会阻塞掉,等待客户端的输入(i = stream.Read(bytes, 0, bytes.Length)) != 0,这个不知道如何判断客户端断开,所以用了try catch比较low的办法。

Byte[] bytes = new Byte[1024]; 
String data = null; 
NetworkStream stream = client.GetStream(); 
int i; 
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) 
{ 
    if (client == null || !client.Connected) 
    { 
        break; 
    } 
    data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); 
    this.ShowMsg(string.Format("收到消息: {0}", data)); 
    data = data.ToUpper(); 
    byte[] msg = System.Text.Encoding.ASCII.GetBytes(data); 
    stream.Write(msg, 0, msg.Length); 
    this.ShowMsg(string.Format("返回消息: {0}", data)); 
}                     

要能关闭服务器端的监听

另外也没有发现如何关闭服务器端的监听,我看了一下stackoverflow,也没发现特别好的办法。代码如下:

public void Close() 
{ 
    this.StatusOn = false; 
    foreach (var client in this.clientList) 
    { 
        if (client != null && client.Connected) 
        { 
            client.Close(); 
        } 
    } 
    this.clientList.Clear(); 
    this.serverListener.Server.Close(); 
    this.serverListener.Stop(); 
    this.ShowMsg("停止监视,关闭连接"); 
} 

全部代码

using log4net; 
using System; 
using System.Collections.Generic; 
using System.Net; 
using System.Net.Sockets; 
using System.Reflection; 
using System.Text; 
using System.Threading; 
namespace srtc_attools.Bll 
{ 
    public class TcpServer 
    { 
        private static TcpServer inst; 
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 
        private List<TcpClient> clientList; 
        private TcpListener serverListener; 
        public Action<string> ShowMsg { get; set; } 
        public bool StatusOn { get; set; } 
    
        private TcpServer() { } 
        public static TcpServer GetInst() 
        { 
            if (inst == null) 
            { 
                inst = new TcpServer(); 
            } 
            return inst; 
        } 
        private Thread threadListen; 
        public void Open(string ip, int port) 
        { 
            this.clientList = new List<TcpClient>(); 
            this.StatusOn = true; 
            this.ShowMsg("开始监视,等待连接"); 
            this.serverListener = new TcpListener(IPAddress.Parse(ip), port); 
            this.serverListener.Start(); 
            threadListen = new Thread(() => ThreadListen()); 
            threadListen.Start(); 
        } 
 
        private void ThreadListen() 
        { 
            while (this.StatusOn) 
            { 
                try 
                { 
                    TcpClient client = this.serverListener.AcceptTcpClient(); 
                    this.clientList.Add(client); 
                    this.ShowMsg(string.Format("客户端连接成功! ip = {0} port = {1}", ((IPEndPoint)client.Client.RemoteEndPoint).Address, ((IPEndPoint)client.Client.RemoteEndPoint).Port)); 
                    Thread t1 = new Thread(() => ThreadHandleMsg(client)); 
                    t1.Start(); 
                } 
                catch (Exception ex) 
                { 
                    Log.Error("", ex); 
                } 
            } 
        } 
        private void ThreadHandleMsg(TcpClient client) 
        { 
            if (client.Connected) 
            { 
                try 
                { 
                    Byte[] bytes = new Byte[1024]; 
                    String data = null; 
                    NetworkStream stream = client.GetStream(); 
                    int i; 
                    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) 
                    { 
                        if (client == null || !client.Connected) 
                        { 
                            break; 
                        } 
                        data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); 
                        this.ShowMsg(string.Format("收到消息: {0}", data)); 
                        data = data.ToUpper(); 
                        byte[] msg = System.Text.Encoding.ASCII.GetBytes(data); 
                        stream.Write(msg, 0, msg.Length); 
                        this.ShowMsg(string.Format("返回消息: {0}", data)); 
                    } 
                } 
                catch (Exception ex) 
                { 
                    Log.Error("客户端发生错误/r/n", ex); 
                    if(this.clientList.Contains(client)) 
                    { 
                        this.clientList.Remove(client); 
                        this.ShowMsg(string.Format("客户端断开连接! ip = {0} port = {1}", ((IPEndPoint)client.Client.RemoteEndPoint).Address, ((IPEndPoint)client.Client.RemoteEndPoint).Port)); 
                    } 
                } 
            } 
        } 
        public void Close() 
        { 
            this.StatusOn = false; 
            foreach (var client in this.clientList) 
            { 
                if (client != null && client.Connected) 
                { 
                    client.Close(); 
                } 
            } 
            this.clientList.Clear(); 
            this.serverListener.Server.Close(); 
            this.serverListener.Stop(); 
            this.ShowMsg("停止监视,关闭连接"); 
        } 
    } 
} 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/20951.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论