C#网络编程TCP通信实例程序简单设计

2023-11-04

 用TcpClient和TcpListener设计一个Tcp通信的例子。

通信程序截图:

2个客户端链接服务端测试截图:

服务端:

客户端

 

运行动态图

 

C#程序设计代码

BenXHSocket.dll主要代码设计

SocketObject类

/*****************************************************
 * ProjectName:  BenXHSocket
 * Description:
 * ClassName:    SocketObject
 * CLRVersion:   4.0.30319.18408
 * Author:       JiYF
 * NameSpace:    BenXHSocket
 * MachineName:  JIYONGFEI
 * CreateTime:   2017/3/31 12:13:06
 * UpdatedTime:  2017/3/31 12:13:06
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace BenXHSocket
{
    /// <summary>
    /// Socket基础类
    /// </summary>
    public abstract class SocketObject
    {
        /// <summary>
        /// 初始化Socket方法
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        public abstract void InitSocket(IPAddress ipAddress,int port);
        public abstract void InitSocket(string ipAddress,int port);

        /// <summary>
        /// Socket启动方法
        /// </summary>
        public abstract void Start();

        /// <summary>
        /// Sockdet停止方法
        /// </summary>
        public abstract void Stop();

    }
}

sockets类

/*****************************************************
 * ProjectName:  BenXHSocket
 * Description:
 * ClassName:    Sockets
 * CLRVersion:   4.0.30319.18408
 * Author:       JiYF
 * NameSpace:    BenXHSocket
 * MachineName:  JIYONGFEI
 * CreateTime:   2017/3/31 12:16:10
 * UpdatedTime:  2017/3/31 12:16:10
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace BenXHSocket
{
    public class Sockets
    {
        /// <summary>
        /// 接收缓冲区大小8k
        /// </summary>
        public byte[] RecBuffer = new byte[8 * 1024]; 
 
        /// <summary>
        /// 发送缓冲区大小8k
        /// </summary>
        public byte[] SendBuffer = new byte[8 * 1024];

        /// <summary>
        /// 异步接收后包的大小
        /// </summary>
        public int Offset { get;set;}

        /// <summary>
        /// 当前IP地址,端口号
        /// </summary>
        public IPEndPoint Ip { get; set; }
        /// <summary>
        /// 客户端主通信程序
        /// </summary>
        public TcpClient Client { get; set; }
        /// <summary>
        /// 承载客户端Socket的网络流
        /// </summary>
        public NetworkStream nStream { get; set; }

        /// <summary>
        /// 发生异常时不为null.
        /// </summary>
        public Exception ex { get; set; }

        /// <summary>
        /// 新客户端标识.如果推送器发现此标识为true,那么认为是客户端上线
        /// 仅服务端有效
        /// </summary>
        public bool NewClientFlag { get; set; }

        /// <summary>
        /// 客户端退出标识.如果服务端发现此标识为true,那么认为客户端下线
        /// 客户端接收此标识时,认为客户端异常.
        /// </summary>
        public bool ClientDispose { get; set; }

        /// <summary>
        /// 空参构造
        /// </summary>
        public Sockets() { }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ip">ip节点</param>
        /// <param name="client">TCPClient客户端</param>
        /// <param name="ns">NetworkStream </param>
        public Sockets(IPEndPoint ip,TcpClient client,NetworkStream ns)
        {
            this.Ip = ip;
            this.Client = client;
            this.nStream = ns;
        }
    }
}

SocketsHandler类

/*****************************************************
 * ProjectName:  BenXHSocket
 * Description:
 * ClassName:    SocketsHandler
 * CLRVersion:   4.0.30319.18408
 * Author:       JiYF
 * NameSpace:    BenXHSocket
 * MachineName:  JIYONGFEI
 * CreateTime:   2017/3/31 13:42:48
 * UpdatedTime:  2017/3/31 13:42:48
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BenXHSocket
{
    /// <summary>
    /// 推送器
    /// </summary>
    /// <param name="sockets"></param>
    public delegate void PushSockets(Sockets sockets);
    
}

BXHTcpServer类 tcp服务端监听类

/*****************************************************
 * ProjectName:  BenXHSocket
 * Description:
 * ClassName:    TcpServer
 * CLRVersion:   4.0.30319.18408
 * Author:       JiYF
 * NameSpace:    BenXHSocket
 * MachineName:  JIYONGFEI
 * CreateTime:   2017/3/31 12:24:08
 * UpdatedTime:  2017/3/31 12:24:08
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;

namespace BenXHSocket
{
    /// <summary>
    /// TCPServer类 服务端程序
    /// </summary>
    public class BXHTcpServer:SocketObject
    {
        private bool IsStop = false;
        object obj = new object();
        public static PushSockets pushSockets;

        /// <summary>
        /// 信号量
        /// </summary>
        private Semaphore semap = new Semaphore(5,5000);

        /// <summary>
        /// 客户端列表集合
        /// </summary>
        public List<Sockets> ClientList = new List<Sockets>();

        /// <summary>
        /// 服务端实例对象
        /// </summary>
        public TcpListener Listener;

        /// <summary>
        /// 当前的ip地址
        /// </summary>
        private IPAddress IpAddress;

        /// <summary>
        /// 初始化消息
        /// </summary>
        private string InitMsg = "JiYF笨小孩TCP服务端";

        /// <summary>
        /// 监听的端口
        /// </summary>
        private int Port;

        /// <summary>
        /// 当前ip和端口节点对象
        /// </summary>
        private IPEndPoint Ip;


        /// <summary>
        /// 初始化服务器对象
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        public override void InitSocket(IPAddress ipAddress, int port)
        {
            this.IpAddress = ipAddress;
            this.Port = port;
            this.Listener = new TcpListener(IpAddress,Port);
        }

        /// <summary>
        /// 初始化服务器对象
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        public override void InitSocket(string ipAddress, int port)
        {
            this.IpAddress = IPAddress.Parse(ipAddress);
            this.Port = port;
            this.Ip = new IPEndPoint(IpAddress,Port);
            this.Listener = new TcpListener(IpAddress,Port);
        }

        /// <summary>
        /// 服务端启动监听,处理链接
        /// </summary>
        public override void Start()
        {
            try
            { 
                Listener.Start();
                Thread Accth = new Thread(new ThreadStart(
                    delegate
                    {
                        while(true)
                        {
                            if(IsStop != false)
                            {
                                break;
                            }
                            this.GetAcceptTcpClient();
                            Thread.Sleep(1);
                        }
                    }
                    ));
                Accth.Start();
            }
            catch(SocketException skex)
            {
                Sockets sks = new Sockets();
                sks.ex = skex;
                pushSockets.Invoke(sks);
            }
        }

        /// <summary>
        /// 获取处理新的链接请求
        /// </summary>
        private void GetAcceptTcpClient()
        {
            try
            { 
                if(Listener.Pending())
                {
                    semap.WaitOne();
                    //接收到挂起的客户端请求链接
                    TcpClient tcpClient = Listener.AcceptTcpClient();

                    //维护处理客户端队列
                    Socket socket = tcpClient.Client;
                    NetworkStream stream = new NetworkStream(socket,true);
                    Sockets sks = new Sockets(tcpClient.Client.RemoteEndPoint as IPEndPoint,tcpClient,stream);
                    sks.NewClientFlag = true;

                    //推送新的客户端连接信息
                    pushSockets.Invoke(sks);

                    //客户端异步接收数据
                    sks.nStream.BeginRead(sks.RecBuffer,0,sks.RecBuffer.Length,new AsyncCallback(EndReader),sks);
                    
                    //加入客户端队列
                    this.AddClientList(sks);

                    //链接成功后主动向客户端发送一条消息
                    if(stream.CanWrite)
                    {
                        byte[] buffer = Encoding.UTF8.GetBytes(this.InitMsg);
                        stream.Write(buffer, 0, buffer.Length);
                    }
                    semap.Release();
                }
            }
            catch
            {
                return;
            }
        }

        /// <summary>
        /// 异步接收发送的的信息
        /// </summary>
        /// <param name="ir"></param>
        private void EndReader(IAsyncResult ir)
        {
            Sockets sks = ir.AsyncState as Sockets;
            if (sks != null && Listener != null)
            {
                try
                {
                    if (sks.NewClientFlag || sks.Offset != 0)
                    {
                        sks.NewClientFlag = false;
                        sks.Offset = sks.nStream.EndRead(ir);
                        //推送到UI
                        pushSockets.Invoke(sks);
                        sks.nStream.BeginRead(sks.RecBuffer,0,sks.RecBuffer.Length,new AsyncCallback(EndReader),sks);
                    }
                }
                catch(Exception skex)
                {
                    lock (obj)
                    {
                        ClientList.Remove(sks);
                        Sockets sk = sks;
                        //标记客户端退出程序
                        sk.ClientDispose = true;
                        sk.ex = skex;
                        //推送至UI
                        pushSockets.Invoke(sks);
                    }
                }
            }
        }

        /// <summary>
        /// 客户端加入队列
        /// </summary>
        /// <param name="sk"></param>
        private void AddClientList(Sockets sk)
        {
            lock (obj)
            {
                Sockets sockets = ClientList.Find(o => { return o.Ip == sk.Ip; });
                if (sockets == null)
                {
                    ClientList.Add(sk);
                }
                else
                {
                    ClientList.Remove(sockets);
                    ClientList.Add(sk);
                }
            }
        }

        /// <summary>
        /// 服务端停止监听
        /// </summary>
        public override void Stop()
        {
            if (Listener != null)
            {
                Listener.Stop();
                Listener = null;
                IsStop = true;
                pushSockets = null;
            }
        }

        /// <summary>
        /// 向所有在线客户端发送消息
        /// </summary>
        /// <param name="SendData">消息内容</param>
        public void SendToAll(string SendData)
        {
            for (int i = 0; i < ClientList.Count; i++)
            {
                SendToClient(ClientList[i].Ip, SendData);
            }
        }

        /// <summary>
        /// 向单独的一个客户端发送消息
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="SendData"></param>
        public void SendToClient(IPEndPoint ip,string SendData)
        {
            try
            {
                Sockets sks = ClientList.Find(o => { return o.Ip == ip; });
                if(sks == null || !sks.Client.Connected)
                {
                    Sockets ks = new Sockets();
                    //标识客户端下线
                    sks.ClientDispose = true;
                    sks.ex = new Exception("客户端没有连接");
                    pushSockets.Invoke(sks);
                }
                if(sks.Client.Connected)
                {
                     //获取当前流进行写入.
                        NetworkStream nStream = sks.nStream;
                        if (nStream.CanWrite)
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes(SendData);
                            nStream.Write(buffer, 0, buffer.Length);
                        }
                        else
                        {
                            //避免流被关闭,重新从对象中获取流
                            nStream = sks.Client.GetStream();
                            if (nStream.CanWrite)
                            {
                                byte[] buffer = Encoding.UTF8.GetBytes(SendData);
                                nStream.Write(buffer, 0, buffer.Length);
                            }
                            else
                            {
                                //如果还是无法写入,那么认为客户端中断连接.
                                ClientList.Remove(sks);
                                Sockets ks = new Sockets();
                                sks.ClientDispose = true;//如果出现异常,标识客户端下线
                                sks.ex = new Exception("客户端无连接");
                                pushSockets.Invoke(sks);//推送至UI

                            }
                        } 
                }
            }
            catch(Exception skex)
            { 
                Sockets sks = new Sockets();
                    sks.ClientDispose = true;//如果出现异常,标识客户端退出
                    sks.ex = skex;
                    pushSockets.Invoke(sks);//推送至UI
            }
        }
    }
}

BXHTcpClient 类 Tcp客户端类

/*****************************************************
 * ProjectName:  BenXHSocket
 * Description:
 * ClassName:    BxhTcpClient
 * CLRVersion:   4.0.30319.42000
 * Author:       JiYF
 * NameSpace:    BenXHSocket
 * MachineName:  JIYF_PC
 * CreateTime:   2017/3/31 20:31:48
 * UpdatedTime:  2017/3/31 20:31:48
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace BenXHSocket
{
    public class BXHTcpClient : SocketObject
    {
            bool IsClose = false;

            /// <summary>
            /// 当前管理对象
            /// </summary>
            Sockets sk;

            /// <summary>
            /// 客户端
            /// </summary>
           public TcpClient client;

            /// <summary>
            /// 当前连接服务端地址
            /// </summary>
            IPAddress Ipaddress;

            /// <summary>
            /// 当前连接服务端端口号
            /// </summary>
            int Port;

            /// <summary>
            /// 服务端IP+端口
            /// </summary>
            IPEndPoint ip;

            /// <summary>
            /// 发送与接收使用的流
            /// </summary>
            NetworkStream nStream;
        
          

            /// <summary>
            /// 初始化Socket
            /// </summary>
            /// <param name="ipaddress"></param>
            /// <param name="port"></param>
            public override void InitSocket(string ipaddress, int port)
            {
                Ipaddress = IPAddress.Parse(ipaddress);
                Port = port;
                ip = new IPEndPoint(Ipaddress, Port);
                client = new TcpClient();
            }

            public static PushSockets pushSockets;
            public void SendData(string SendData)
            {
                try
                {

                    if (client == null || !client.Connected)
                    {
                        Sockets sks = new Sockets();
                        sks.ex = new Exception("客户端无连接..");
                        sks.ClientDispose = true;
                        
                        pushSockets.Invoke(sks);//推送至UI 
                    }
                    if (client.Connected) //如果连接则发送
                    {
                        if (nStream == null)
                        {
                            nStream = client.GetStream();
                        }
                        byte[] buffer = Encoding.UTF8.GetBytes(SendData);
                        nStream.Write(buffer, 0, buffer.Length);
                    }
                }
                catch (Exception skex)
                {
                    Sockets sks = new Sockets();
                    sks.ex = skex;
                    sks.ClientDispose = true;
                    pushSockets.Invoke(sks);//推送至UI
                }
            }
            /// <summary>
            /// 初始化Socket
            /// </summary>
            /// <param name="ipaddress"></param>
            /// <param name="port"></param>
            public override void InitSocket(IPAddress ipaddress, int port)
            {
                Ipaddress = ipaddress;
                Port = port;
                ip = new IPEndPoint(Ipaddress, Port);
                client = new TcpClient();
            }
            private void Connect()
            {
                client.Connect(ip);
                nStream = new NetworkStream(client.Client, true);
                sk = new Sockets(ip, client, nStream);
                sk.nStream.BeginRead(sk.RecBuffer, 0, sk.RecBuffer.Length, new AsyncCallback(EndReader), sk);
            }
            private void EndReader(IAsyncResult ir)
            {

                Sockets s = ir.AsyncState as Sockets;
                try
                {
                    if (s != null)
                    {

                        if (IsClose && client == null)
                        {
                            sk.nStream.Close();
                            sk.nStream.Dispose();
                            return;
                        }
                        s.Offset = s.nStream.EndRead(ir);
                        pushSockets.Invoke(s);//推送至UI
                        sk.nStream.BeginRead(sk.RecBuffer, 0, sk.RecBuffer.Length, new AsyncCallback(EndReader), sk);
                    }
                }
                catch (Exception skex)
                {
                    Sockets sks = s;
                    sks.ex = skex;
                    sks.ClientDispose = true;
                    pushSockets.Invoke(sks);//推送至UI

                }

            }
            /// <summary>
            /// 重写Start方法,其实就是连接服务端
            /// </summary>
            public override void Start()
            {
                Connect();
            }
            public override void Stop()
            {
                Sockets sks = new Sockets();
                if (client != null)
                {
                    client.Client.Shutdown(SocketShutdown.Both);
                    Thread.Sleep(10);
                    client.Close();
                    IsClose = true;
                    client = null;
                }
                else
                {
                    sks.ex = new Exception("客户端没有初始化.!");
                }
                pushSockets.Invoke(sks);//推送至UI
            }

        }
}

服务端和客户端窗体应用程序主要方法设计实现

服务端窗体应用程序主要方法代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.Net;
using BenXHSocket;
using System.Threading;

namespace BenXHSocketTcpServer
{
    public partial class FrmTCPServer : Form
    {
        private static string serverIP;
        private static int port;
        object obj = new object();
        private int sendInt = 0;
        private static Dictionary<TreeNode, IPEndPoint> DicTreeIPEndPoint = new Dictionary<TreeNode, IPEndPoint>();

        public FrmTCPServer()
        {
            InitializeComponent();
            
            serverIP = ConfigurationManager.AppSettings["ServerIP"];
            port = int.Parse(ConfigurationManager.AppSettings["ServerPort"]);
            Control.CheckForIllegalCrossThreadCalls = false;
            init();
        }

        private void init()
        {
            treeViewClientList.Nodes.Clear();
            TreeNode tn = new TreeNode();
            tn.Name = "ClientList";
            tn.Text = "客户端列表";
            tn.ImageIndex = 0;
            tn.ContextMenuStrip = contextMenuStripClientAll;
            treeViewClientList.Nodes.Add(tn);
            DicTreeIPEndPoint.Clear();

            //自已绘制  
            this.treeViewClientList.DrawMode = TreeViewDrawMode.OwnerDrawText;
            this.treeViewClientList.DrawNode += new DrawTreeNodeEventHandler(treeViewClientList_DrawNode);
        }

        private BenXHSocket.BXHTcpServer tcpServer;


        /// <summary>
        /// 绘制颜色
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void treeViewClientList_DrawNode(object sender, DrawTreeNodeEventArgs e)
        {
            e.DrawDefault = true; //我这里用默认颜色即可,只需要在TreeView失去焦点时选中节点仍然突显  
            return;
            //or  自定义颜色  
            if ((e.State & TreeNodeStates.Selected) != 0)
            {
                //演示为绿底白字  
                e.Graphics.FillRectangle(Brushes.DarkBlue, e.Node.Bounds);

                Font nodeFont = e.Node.NodeFont;
                if (nodeFont == null) nodeFont = ((TreeView)sender).Font;
                e.Graphics.DrawString(e.Node.Text, nodeFont, Brushes.White, Rectangle.Inflate(e.Bounds, 2, 0));
            }
            else
            {
                e.DrawDefault = true;
            }

            if ((e.State & TreeNodeStates.Focused) != 0)
            {
                using (Pen focusPen = new Pen(Color.Black))
                {
                    focusPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                    Rectangle focusBounds = e.Node.Bounds;
                    focusBounds.Size = new Size(focusBounds.Width - 1,
                    focusBounds.Height - 1);
                    e.Graphics.DrawRectangle(focusPen, focusBounds);
                }
            }

        }  

        /// <summary>
        /// 开启服务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StartServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (serverIP != null && serverIP != "" && port != null && port >= 0)
                {
                    tcpServer.InitSocket(IPAddress.Parse(serverIP), port);
                    tcpServer.Start();
                    listBoxServerInfo.Items.Add(string.Format("{0}服务端程序监听启动成功!监听:{1}:{2}",DateTime.Now.ToString(), serverIP, port.ToString()));
                    StartServerToolStripMenuItem.Enabled = false;
                }

                
            }
            catch(Exception ex)
            {
                listBoxServerInfo.Items.Add(string.Format("服务器启动失败!原因:{0}",ex.Message));
                StartServerToolStripMenuItem.Enabled = true;
            }
        }

        /// <summary>
        /// 停止服务监听
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StopServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tcpServer.Stop();
            listBoxServerInfo.Items.Add("服务器程序停止成功!");
            StartServerToolStripMenuItem.Enabled = true;
           
        }

        private void FrmTCPServer_Load(object sender, EventArgs e)
        {
            if(tcpServer ==null)
            listBoxServerInfo.Items.Add(string.Format("服务端监听程序尚未开启!{0}:{1}",serverIP,port));
            treeViewClientList.ExpandAll();
            BXHTcpServer.pushSockets = new PushSockets(Rev);
            tcpServer = new BXHTcpServer();
        }

        /// <summary>
        /// 处理接收到客户端的请求和数据
        /// </summary>
        /// <param name="sks"></param>
        private void Rev(BenXHSocket.Sockets sks)
        {
            this.Invoke(new ThreadStart(
                delegate
                {
                    if (treeViewClientList.Nodes[0] != null)
                    { 
                        
                    }

                    if (sks.ex != null)
                    {
                        if (sks.ClientDispose)
                        {
                            listBoxServerInfo.Items.Add(string.Format("{0}客户端:{1}下线!",DateTime.Now.ToString(), sks.Ip));
                            if (treeViewClientList.Nodes[0].Nodes.ContainsKey(sks.Ip.ToString()))
                            {
                                if (DicTreeIPEndPoint.Count != 0)
                                {
                                    removTreeIPEndPoint(sks.Ip);
                                    treeViewClientList.Nodes[0].Nodes.RemoveByKey(sks.Ip.ToString());

                                    toolStripStatusLabelClientNum.Text = (int.Parse(toolStripStatusLabelClientNum.Text) - 1).ToString();//treeViewClientList.Nodes[0].Nodes.Count.ToString();
                           
                                }
                               
                               }
                        }
                        listBoxServerInfo.Items.Add(sks.ex.Message);
                    }
                    else
                    {
                        if (sks.NewClientFlag)
                        {
                            listBoxServerInfo.Items.Add(string.Format("{0}新的客户端:{0}链接成功",DateTime.Now.ToString(), sks.Ip));
                            
                            TreeNode tn = new TreeNode();
                            tn.Name = sks.Ip.ToString();
                            tn.Text = sks.Ip.ToString();
                            tn.ContextMenuStrip = contextMenuStripClientSingle;
                            tn.Tag = "客户端";
                            tn.ImageIndex = 1;

                            treeViewClientList.Nodes[0].Nodes.Add(tn);

                            //treeview节点和IPEndPoint绑定
                            DicTreeIPEndPoint.Add(tn,sks.Ip);

                            if (treeViewClientList.Nodes[0].Nodes.Count > 0)
                            {
                                treeViewClientList.ExpandAll();
                            }
                            toolStripStatusLabelClientNum.Text = (int.Parse(toolStripStatusLabelClientNum.Text)+1).ToString();
                        }
                        else if (sks.Offset == 0)
                        {
                            listBoxServerInfo.Items.Add(string.Format("{0}客户端:{1}下线.!",DateTime.Now.ToString(), sks.Ip));
                            if (treeViewClientList.Nodes[0].Nodes.ContainsKey(sks.Ip.ToString()))
                            {
                                if (DicTreeIPEndPoint.Count != 0)
                                {
                                    removTreeIPEndPoint(sks.Ip);
                                    treeViewClientList.Nodes[0].Nodes.RemoveByKey(sks.Ip.ToString());

                                    toolStripStatusLabelClientNum.Text = (int.Parse(toolStripStatusLabelClientNum.Text) - 1).ToString();
                            
                                }
                            }
                        }
                        else
                        {
                            byte[] buffer = new byte[sks.Offset];
                            Array.Copy(sks.RecBuffer, buffer, sks.Offset);
                            string str = Encoding.UTF8.GetString(buffer);
                            listBox1.Items.Add(string.Format("{0}客户端{1}发来消息:{2}",DateTime.Now.ToString(), sks.Ip, str));
                        }
                    }
                }
                )
                );
        }

        /// <summary>
        /// 关闭程序钱停止服务器实例
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmTCPServer_FormClosing(object sender, FormClosingEventArgs e)
        {
            tcpServer.Stop();
        }

        private void treeViewClientList_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //
        }

        private void treeViewClientList_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                treeViewClientList.Focus();
                treeViewClientList.SelectedNode = treeViewClientList.GetNodeAt(e.X,e.Y);
            }

        }


        private void toolStripMenuSendSingle_Click(object sender, EventArgs e)
        {
            if (treeViewClientList.SelectedNode != null)
            {
                tcpServer.SendToClient(DicTreeIPEndPoint[treeViewClientList.SelectedNode], string.Format("服务端单个消息...{0}", sendInt.ToString()));
                sendInt++;
            }
        }

        private void toolStripMenuSendAll_Click(object sender, EventArgs e)
        {
            tcpServer.SendToAll("服务端全部发送消息..." + sendInt);
            sendInt++;
        }

        private void removTreeIPEndPoint(IPEndPoint ipendPoint)
        {

            if (DicTreeIPEndPoint.Count <= 0) return;
            //foreach遍历Dictionary时候不能对字典进行Remove
            TreeNode[] keys = new TreeNode[DicTreeIPEndPoint.Count];
            DicTreeIPEndPoint.Keys.CopyTo(keys,0);
            lock (obj)
            {
                foreach (TreeNode item in keys)
                {
                    if (DicTreeIPEndPoint[item] == ipendPoint)
                    {
                        DicTreeIPEndPoint.Remove(item);
                    }
                }
            }
        }

    }
}

客户端窗体应用程序主要代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using BenXHSocket;
using System.Threading;

namespace BenXHSocketClient
{
    public partial class FrmTCPClient : Form
    {
        BXHTcpClient tcpClient;
        
        string ip = string.Empty;
        string port = string.Empty;
        private int sendInt = 0;
        public FrmTCPClient()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void btnConnServer_Click(object sender, EventArgs e)
        {
            try
            {
                this.ip = txtServerIP.Text.Trim();
                this.port = txtServerPort.Text.Trim();

                tcpClient.InitSocket(ip, int.Parse(port));
                tcpClient.Start();
                listBoxStates.Items.Add("连接成功!");
                btnConnServer.Enabled = false;

            }
            catch (Exception ex)
            {

                listBoxStates.Items.Add(string.Format("连接失败!原因:{0}", ex.Message));
                btnConnServer.Enabled = true;
            }
        }

        private void FrmTCPClient_Load(object sender, EventArgs e)
        {
            //客户端如何处理异常等信息参照服务端
         
            BXHTcpClient.pushSockets = new PushSockets(Rec);

            tcpClient = new BXHTcpClient();
            this.ip = txtServerIP.Text.Trim();
            this.port = txtServerPort.Text.Trim();
          
        }

        /// <summary>
        /// 处理推送过来的消息
        /// </summary>
        /// <param name="rec"></param>
        private void Rec(BenXHSocket.Sockets sks)
        {
            this.Invoke(new ThreadStart(delegate
            {
                if (listBoxText.Items.Count > 1000)
                {
                    listBoxText.Items.Clear();
                }
                if (sks.ex != null)
                {
                    if (sks.ClientDispose == true)
                    {
                        //由于未知原因引发异常.导致客户端下线.   比如网络故障.或服务器断开连接.
                        listBoxStates.Items.Add(string.Format("客户端下线.!"));
                    }
                    listBoxStates.Items.Add(string.Format("异常消息:{0}", sks.ex));
                }
                else if (sks.Offset == 0)
                {
                    //客户端主动下线
                    listBoxStates.Items.Add(string.Format("客户端下线.!"));
                }
                else
                {
                    byte[] buffer = new byte[sks.Offset];
                    Array.Copy(sks.RecBuffer, buffer, sks.Offset);
                    string str = Encoding.UTF8.GetString(buffer);
                    listBoxText.Items.Add(string.Format("服务端{0}发来消息:{1}", sks.Ip, str));
                }
            }));
        }

        private void btnDisConn_Click(object sender, EventArgs e)
        {
            tcpClient.Stop();
            btnConnServer.Enabled = true;
        }

        private void btnSendData_Click(object sender, EventArgs e)
        {
            tcpClient.SendData("客户端消息!" + sendInt);
            sendInt++;
            
        }

        private void btnConnTest_Click(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(o =>
            {
                for (int i = 0; i < 100; i++)
                {
                    BenXHSocket.BXHTcpClient clientx= new  BenXHSocket.BXHTcpClient();//初始化类库  
                    clientx.InitSocket(ip, int.Parse(port));
                    clientx.Start();
                }
                MessageBox.Show("完成.!");
            });
        }


    }
}

运行程序下载:

BenXHSocket程序下载 

源代码工程文件下载

BenXHSocket.dll      主要程序动态库

BenXHSocketClient.exe   客户端应用程序

BenXHSocketTcpServer.exe  服务端应用程序

BenXHSocketTcpServer.exe.config  服务端应用程序配置文件

其中:BenXHSocketTcpServer.exe.config为配置文件,可以设置监听的ip地址和端口号,默认ip地址:127.0.0.1 默认的端口号:4455

https://www.cnblogs.com/JiYF/p/6699104.html

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#网络编程TCP通信实例程序简单设计 的相关文章

  • Qt 图表和数据可视化小部件

    我已经安装了 Qt 5 7 来尝试 Qt 图表和 Qt 数据可视化 但我在 Qt Designer 和 Qt Creator 中都找不到新的小部件 有什么建议我应该做什么才能让新的小部件出现在设计器中 我今天遇到了完全相同的问题 默认情况下
  • 生成多个随机数

    我想生成 25 个唯一的随机数并将它们列在控制台中 数字的长度应至少为 10 个字符 有什么简单的方法可以做到这一点吗 尝试将数字构建为字符串 并使用 HashSet 确保它们是唯一的 Random random new Random Ha
  • ASP.NET Web 应用程序中的身份验证遇到问题

    我正在尝试对从登录页面登录我的 Web 应用程序的用户进行身份验证 我正在使用本教程 http support microsoft com kb 301240作为指南 它几乎准确地解释了我希望做什么 但是当我输入用户名和密码时 验证不起作用
  • .crt 部分?这个警告是什么意思?

    我最近收到此警告 VC 2010 warning LNK4210 CRT section exists there may be unhandled static initializers or terminators 我假设这是关键部分
  • 自动映射器多对多 stackoverflowException

    我遇到以下映射的堆栈溢出 Mapper CreateMap
  • 最新 .Net MongoDb.Driver 的连接问题

    我创建了一个 MongoLab 沙箱数据库 我与 MongoChef 连接 效果很好 我通过 Nuget 安装了 MongoDB Driver 2 2 2 我编写了一些简单的 C 演示代码 但就是无法使其工作 连接字符串是直接从 Mongo
  • C# 无法捕获 SerializationException

    我的程序在加载序列化文件的部分遇到问题 如果文件无法反序列化 我希望很好地失败 但由于某种原因 我的程序将中断而不是进入 catch 子句 这是我的代码 using FileStream fs new FileStream openFile
  • 如何在C中同时运行两个子进程?

    所以我开始学习并发编程 但由于某种原因我什至无法掌握基础知识 我有一个名为 fork c 的文件 其中包含一个 main 方法 在此方法中 我将 main 分叉两次 分别进入子进程 1 和 2 在孩子 1 中 我打印了字符 A 50 次 在
  • Visual Studio 中列表框的上移、下移按钮[重复]

    这个问题在这里已经有答案了 我正在尝试制作一个上移按钮和一个下移按钮 以移动 Microsoft Visual Studio 2012 中列表框中的选定项目 我已经在 WDF jquery winforms 和其他一些表单中看到了其他示例
  • .NET 5 EF Core SaveChangesAsync 因错误而挂起

    尽管这个问题有很多结果 但没有一个真正给我明确的答案 每次我尝试通过 AddAsync 和 SaveChangesAsync 方法插入错误数据 例如重复的主键 时 我都会看到以下日志 执行 DbCommand 失败 15 毫秒 我还在 SQ
  • 我在使用 ado.net 时收到错误 Argument 2 may not be pass with ref keywords

    int t 0 cmd Parameters AddWithValue Res ref t 我在第二行收到错误 参数 2 不能与 ref 关键字一起传递 您只能通过引用传递参数ref if the 范围 is a ref参数也是如此 Add
  • 如何从外语线程调用Python函数(C++)

    我正在开发一个程序 使用 DirectShow 来抓取音频数据 媒体文件 DirectShow 使用线程将音频数据传递给回调 我的程序中的函数 然后我让该回调函数调用另一个函数 Python 中的函数 我使用 Boost Python 来包
  • 配置:错误:无法运行C编译的程序

    我正在尝试使用 Debian Wheezy 操作系统在我的 Raspberry Pi 上安装不同的软件 当我运行尝试配置软件时 我尝试安装我得到此输出 checking for C compiler default output file
  • 您对“大规模 C++ 软件设计”的看法 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 正在阅读亚马逊评论 https rads stackoverflow com amzn click com 0201633620 and ACC
  • 传递数组时在 C 中的函数参数中强制指定数组大小

    Context 在 C 中 我有一个以数组作为参数的函数 该参数用作该函数的输出 输出的大小始终相同 我会 让阅读代码的人清楚所需的大小 不过它已经在函数注释中了 理想情况下 编译会输出警告或错误 这样我就可以在编译时而不是运行时防止出现问
  • valgrind 在 Raspberry Pi 上返回未处理的指令

    我最近一直在尝试在运行 Debian GNU Linux7 0 喘息 的树莓派 型号 b 上使用 valgrind 来调试分段错误 每次我在编译的 C 程序上运行 valgrind 时 都会得到类似以下内容的信息 disInstr arm
  • 连接到没有元数据的网络服务

    我想连接到此网络服务 https training api temando com schema 2009 06 server wsdl https training api temando com schema 2009 06 serve
  • 如何从 Access 数据库中读取“是/否”值作为布尔值?

    帮我找回YES NO来自 MS Access 的布尔格式数据类型 我尝试解析它 但它总是返回 false 更新 实际上不是问题抱歉 它确实接受 YES NO 作为布尔值 OleDbconnection dbConnect new OleDb
  • “1个未解决的外部”C++

    我已经检查了所有文件之间的连接以及类和函数定义 但每次我尝试运行我的程序时 它都会阻止我并告诉我它有 1 个未解析的外部 该程序应该打开多个文件 一个 学生 文件和一个 成绩 文件 从中读取数据 然后使用 查询文件 来查找数据 找到查询中要
  • Xcode 7 调试器不会中断内联标头函数

    过去五年我一直在各种 C 项目中使用 Xcode 没有出现这个问题 今天 我打开了一个较旧的项目 大约 2 年前 并尝试通过在该函数中放置一个活动断点来调试头文件中的内联函数 由于某种原因 调试器不会中断此代码 但是 如果我在调用该函数的

随机推荐

  • SQL注入—搜索注入

    SQL注入 搜索注入 本文仅供学习或参考 实验准备 皮卡丘靶场 SQL Injection 搜索型注入 实验步骤 输入任意字母 以 k 为例 进行模糊查询 查看结果 猜想数据库查询语句 select from table where use
  • Springboot整合 Minio

    Springboot整合 Minio 1 添加依赖
  • VMware Workstation虚拟机无桥接模式以及主机为无线的桥接配置

    目录 一 虚拟机网络设置无桥接模式 二 vmware 11版本 打开vm14 不兼容问题解决 三 主机为无线网络时虚拟机如何配置桥接上网 一 虚拟机网络设置无桥接模式 1 执行WIN R 输入services msc 打开服务管理器 回车
  • 快速解决Emulator: emulator: ERROR: x86 emulation currently requires hardware acceleration!

    问题 Emulator emulator ERROR x86 emulation currently requires hardware acceleration 翻译 Emulator Emulator 错误 x86仿真模拟器当前需要硬件
  • 前端页面的居中问题

    垂直居中 1 设置子块元素的line height的高度为父元素的高度就可以 2 如果子元素为行内元素 可以将子元素display设置为block 水平居中 直接设置 text align center 决定行内元素 实现文字的水平居中 设
  • redis服务器命令方法详解

    redis服务器命令方法详解 指令 BGREWRITEAOF rewrite BGSAVE bgsave FLUSHALL SAVE Sync Slaveof PSYNC redis 2 8 版本 DBSIZE 指令 BGREWRITEAO
  • OpenAI 开发系列(四):掌握OpenAI API调用方法

    全文共4000余字 预计阅读时间约17 30分钟 满满干货 附代码 建议收藏 本文目标 明确获取OpenAI API密钥的流程 理解如何调用OpenAI的各类大模型 并了解其对应的相关参数 代码下载点这里 一 获取OpenAI的API ke
  • 谷歌身份验证怎么登录_使用Google登录身份验证用户

    谷歌身份验证怎么登录 I hate dealing with user authentication so I m very happy to make user management and authentication somebody
  • c#:浅析var关键字

    c 浅析var关键字 1 var关键字介绍 var关键字是c 3 5新增的特性 称为推断类型 弱类型 由var声明的变量 编译器会根据上下文来判断你到底想用什么类型 也就是说当你无法确定自己将使用什么类型时 就可以使用var var类似于o
  • R语言——(四)、数据读入与预处理

    文章目录 一 数据读入 1 直接输入数据 2 读R包中的数据 3 从外部文件读入数据 3 1 读入文本文件 TXT 3 2读入Excel格式文件 3 3读入其它格式文件 SAS数据 SPSS数据 Stata数据等 二 写入数据 三 数据预处
  • Angular Tracy 小笔记 其他 dos 命令,发布

    其他命令 Angular Material ng add angular material Add PWA support ng add angular pwa Add Dependency ng add Run and Watch Tes
  • Java中Steam流的详解

    在Java中 Stream是一种用于操作集合 Collection 和数组的高级抽象 它提供了一种功能强大且表达力丰富的编程模型 可以以声明性的方式对数据进行处理和转换 概述 Stream是Java 8引入的一种新的抽象 它使得我们可以以类
  • python 实现简易的学员管理系统

    文章目录 前言 基本思路 需求实现 1 实现菜单的功能 2 提示用户输入需要进行的操作 并执行相关操作 3 具体函数功能的实现 增加学员信息 显示所有学员信息 删除学员信息 修改学员信息 查询学员信息 整体代码展示 前言 前面我们已经学习了
  • c++数值极限numeric_limits

    一般来说 数值类型的极值是一个与平台相关的特性 c 标准程序库通过template numeric limits提供这些极值 取代传统C语言所采用的预处理常数 你仍然可以使用后者 其中整数常数定义于
  • c++字符串类型string和char数组的互转

    1 string转char include
  • TestFlight 添加测试人员 (内部测试人员)

    用有管理员身份的账号登陆 itunes connect 在登陆页面可以看到如下界面 选择用户和职能 会看到之前已经添加的用户 可以管理用户的app访问权限 找到 添加用户 输入用户的apple id一般是注册时候的邮箱地址形式 添加成功后会
  • GIT代码冲突解决方案,两种方案详细教程

    方法一 先pull 再进行commit 此种方法当工作区文件和远程仓库文件有冲突时不能完成pull的 需要先备份工作区文件 恢复文件与远程服务器一致 才能完成pull 然后将本地修改添加进去 commit push 这种操作修改文件较多时非
  • 如何使用TensorFlow进行序列建模和时间序列预测?

    如何使用TensorFlow进行序列建模和时间序列预测 使用TensorFlow进行序列建模和时间序列预测涉及以下主要步骤 数据准备 首先 你需要准备时间序列数据集 确保数据集包含适当的时间序列信息和相应的目标变量 你可能需要对数据进行预处
  • JVM 的 垃圾回收(GC)超全解析,面试官看了直呼内行!!还不快收藏起来

    我是目录 1 垃圾回收的时机 2 垃圾回收机制 如何判断对象已死 3 需要垃圾回收的内存 4 垃圾回收算法 5 垃圾回收过程 6 垃圾收集器 Garbage Collection GC Java进程在 启动后 会 创建垃圾回收线程 来对 内
  • C#网络编程TCP通信实例程序简单设计

    用TcpClient和TcpListener设计一个Tcp通信的例子 通信程序截图 2个客户端链接服务端测试截图 服务端 客户端 运行动态图 C 程序设计代码 BenXHSocket dll主要代码设计 SocketObject类 Proj