C# socket通信的一般步聚

1、向服务器发出链接请求:

  需要条件:a、服务器IP;b、服务器端口

  实现:

  private IPAddress _ipAddr=IPAddress.Parse("192.168.28.126");

  int Port=8888;

  //向服务器发出连接请求
     TCPConnection conn = new TCPConnection(_ipAddr, port);
     TcpClient _tcpc = conn.Connect();

  //以下为判断是否链接得上

   if (_tcpc == null)
            {
                MessageBox.Show("无法连接到服务器,请重试!",
                                "错误",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Exclamation);
            }
            else
            {
                NetworkStream netstream = _tcpc.GetStream();//提供用于访问网络的基本数据流
                //向服务器发送用户名以确认身份


                netstream.Write(Encoding.Unicode.GetBytes(user_tb.Text), 0, Encoding.Unicode.GetBytes(user_tb.Text).Length);

                //得到登录结果
                byte[] buffer = new byte[50];
                netstream.Read(buffer, 0, buffer.Length);//该方法将数据读入 buffer 参数并返回成功读取的字节数。如果没有可以读取的数据,则 Read 方法返回 0。

                string connResult = Encoding.Unicode.GetString(buffer).TrimEnd('\0');
                if (connResult.Equals("cmd::Failed"))//登录不成功
                {
                    MessageBox.Show("您的用户名已经被使用,请尝试其他用户名!",
                                    "提示",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Information);
                    return;
                }
                else  //登录成功
                {
                    string svrskt = svrip_tb.Text + ":" + svrport_tb.Text;
                    chat_frm chatFrm = new chat_frm(user_tb.Text, netstream, svrskt);//一个巧妙的参数传递方法
                    chatFrm.Owner = this;
                    this.Hide();
                    chatFrm.Show();
                }
            }

2、向服务器发送数据:(逆向推进)

  1)、private NetworkStream _nws = _tcpc.GetStream();// 用于接受和发送的网络流

      ^
                 ||

    TcpClient _tcpc = conn.Connect();

      ^

      ||

    TCPConnection conn = new TCPConnection(_ipAddr, port);//向服务器发出连接请求

      ^

      ||

    private IPAddress _ipAddr=IPAddress.Parse("192.168.28.126");//服务器IP

    int Port=8888;//服务器端口

  2)、发送: _nws.Write(new byte[] { 0, 5 }, 0, 2);//发送广播请求 public override void Write(byte[] buffer, int offset, int size);

      以下为发送给指定用户:

      string _receiver = online_cb.Text;//对方用户

      _nws.Write(Encoding.Unicode.GetBytes(_receiver), 0, Encoding.Unicode.GetBytes(_receiver).Length);

      //以下为发送信息内容

       _nws.Write(Encoding.Unicode.GetBytes(sendTxt), 0, Encoding.Unicode.GetBytes(sendTxt).Length);

3、启动接收信息线程(在page_load里直接启动)

   /// <summary>
        /// 用于接受消息的线程
        /// </summary>
        private Thread _receiveThread = null;

        /// <summary>
        /// 启动接受消息线程并显示相关信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chat_frm_Load(object sender, EventArgs e)
        {
            _receiveThread = new Thread(new ThreadStart(ReceiveMsg));//接下来会执行ReceiveMsg函数
            _receiveThread.Start();

    //以下这些都是相关控件的变化:
            online_cb.Enabled = false;
            user_lb.Text   = "当前用户:" + _username;
            svrskt_lb.Text = "服务器:" + _svrskt;
        }

        /// <summary>
        /// 接受消息的线程执行体
        /// </summary>
        private void ReceiveMsg()
        {
            while (true)
            {
                byte[] packet = new byte[_maxPacket];//_maxPacket:缓冲区的大小:private int _maxPacket = 2048;//2K的缓冲区


      //从 System.Net.Sockets.NetworkStream 读取数据。public override int Read(byte[] buffer, int offset, int size);

               _nws.Read(packet, 0, packet.Length);

                string _cmd = DecodingBytes(packet);

                switch (_cmd)
                {
                    /// "11"-服务器要求客户机更新在线列表
                    /// "12"-服务器要求客户机做闪屏振动
                    /// default-接受用户消息或者系统消息的正文
                    case "11":
                        {
                            byte[] onlineBuff = new byte[_maxPacket];
                            int byteCnt = _nws.Read(onlineBuff, 0, onlineBuff.Length);
                            IFormatter format = new BinaryFormatter();
                            MemoryStream stream = new MemoryStream();
                            stream.Write(onlineBuff, 0, byteCnt);
                            stream.Position = 0;
                            StringCollection onlineList = (StringCollection)format.Deserialize(stream);
                            online_cb.Items.Clear();
                            foreach (string onliner in onlineList)
                            {
                                if (!onliner.Equals(_username))
                                {
                                    online_cb.Items.Add(onliner);
                                }
                            }
                            break;
                        }
                    case "12":
                        {
                            Nudge();
                            break;
                        }
                    default:
                        {
                            string displaytxt = Encoding.Unicode.GetString(packet);
                            chatrcd_rtb.AppendText(displaytxt);
                            _sp1.Play();
                            break;
                        }
                }
            }
        }

二、服务器的相关行为:

1、服务器监听:

  IPAddress _ip = IPAddress.Parse("192.168.28.126");// Dns.GetHostAddresses(Dns.GetHostName())[0];//可能有多个,此时的IP是本地IP
     _tcpl = new TcpListener(_ip, _port);
     _tcpl.Start();//开始侦听传入的连接请求。

  while (true)
      {
                byte[] packetBuff = new byte[_maxPacket];// 接收数据缓冲区大小64K

      /*

                //AcceptSocket 是一个阻止方法,该方法返回可用于发送和接收数据的 Socket。
                //如果希望避免阻止,请使用 Pending 方法来确定传入连接队列中的连接请求是否可用。
                //返回的 Socket 是使用远程主机的 IP 地址和端口号初始化的。
                //您可以使用 Socket 类中任何可用的 Send 和 Receive 方法与远程主机进行通信。
                //------------使用 Socket 后,请确保调用其 Close 方法。如果应用程序相对简单,-----------
                //请考虑使用 AcceptTcpClient 方法代替 AcceptSocket 方法。
                //TcpClient 提供了一些通过网络在阻止同步模式下发送和接收数据的简单方法。

      */

                Socket newClient = _tcpl.AcceptSocket();//本地TcpListener 接受新的请求
                //返回的 Socket 是使用远程主机的 IP 地址和端口号初始化的

      newClient.Receive(packetBuff);//将接受的远程SOCKET,将数据存入接受缓冲区

      //客户端向服务器发送用户名请求:以下为接收

      string userName = Encoding.Unicode.GetString(packetBuff).TrimEnd('\0');

      /*

      //接着就进行相关的处理:

      处理的结果,发送命令给客户端:

     如:

      newClient.Send(Encoding.Unicode.GetBytes("cmd::Failed"));//发送命令为:cmd::Failed

     或newClient.Send(Encoding.Unicode.GetBytes("cmd::Successful"));

      */

     //将新连接加入转发表并创建线程为其服务
                _transmit_tb.Add(userName, newClient);//直接把用户名、Socket对象作为一对值加入转发表

      /*定义如下:

        /// <summary>
            /// 保存所有客户端会话的哈希表
            /// </summary>
            private Hashtable _transmit_tb = new Hashtable();

      */

  }

原文地址:https://www.cnblogs.com/llyfe2006/p/1874668.html