.net socket 通信

最近接触到socket,这个和通信有关 ,比如客户端和服务端 俩个之间交流信息就会用到。

那么socket 是如何实现通信的呢?

对于服务端是这样的

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace _01聊天室服务器
{
    public partial class FormServer : Form
    {
        public FormServer()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;  //检查非法跨线程调用,关闭
        }

        //服务端 监听套接字
        Socket sokWatch = null;
        //服务端 监听线程
        Thread thrWatch = null;
        //字典集合:保存 通信套接字
        Dictionary<string, MsgConnection> dictConn = new Dictionary<string, MsgConnection>();

        #region 1.0 开始监听
        /// <summary>
        /// 开始监听
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMonitor_Click(object sender, EventArgs e)
        {
            try
            {
                //1.0创建监听套接字,使用ip4协议,流式传输,tcp链接
                sokWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //2.0绑定端口
                //2.1获取网络节点对象
                IPAddress address = IPAddress.Parse(txbIp.Text);
                IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txbPort.Text));
                //2.2 绑定端口(其实内部 就向系统的端口表中注册了一个端口,并指定了当前程序句柄)
                sokWatch.Bind(endPoint);
                //2.3 设置监听队列,指限制同时处理的连接请求数,即同时处理的客户端连接请求。
                sokWatch.Listen(10);

                2.4开始监听:此方法会阻断当前线程,直到有其他程序连接过来,才执行完毕;    需重新开启线程
                //sokWatch.Accept();

                //2.4开始监听,调用监听线程 执行 监听套接字的监听方法。
                thrWatch = new Thread(WatchConncting);
                thrWatch.IsBackground = true;
                thrWatch.Start();
                ShowMsg("服务器启动!");
            }
            catch (SocketException soex)
            {
                ShowMsg("异常:" + soex);
            }
            catch (Exception ex)
            {
                ShowMsg("异常:" + ex);
            }
        }
        #endregion

        //开始监听,线程调用
        bool isWatch = true;
        #region 2.0 服务器监听方法 + void WatchConncting()
        void WatchConncting()
        {
            try
            {
                //循环监听客户端的连接请求。
                while (isWatch)
                {
                    //2.4开始监听,返回了一个通信套接字
                    Socket sockMsg = sokWatch.Accept();
                    //2.5 创建通信管理类
                    MsgConnection conn = new MsgConnection(sockMsg, ShowMsg, RemoveClient);

                    //将当前连接成功的【与客户端通信的套接字】的标识保存起来,并显示到列表中
                    //将远程客户端的 ip 和 端口 字符串 存入列表
                    listOnline.Items.Add(sockMsg.RemoteEndPoint.ToString());
                    //将服务器端的通信套接字存入字典集合。
                    dictConn.Add(sockMsg.RemoteEndPoint.ToString(), conn);
                    ShowMsg("有客户端连接了!");
                }
            }
            catch (Exception ex)
            {
                ShowMsg("异常" + ex);
            }
        }
}

还有一个负责通信的类 MsgConnection

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Threading;

namespace _01聊天室服务器
{
    /// <summary>
    /// 通信管理类,负责处理与某个客户端通信的过程
    /// </summary>
    public class MsgConnection
    {
        //与某个客户端通信套接字
        Socket sokMsg = null;
        //通信线程
        Thread thrMsg = null;
        //创建一个委托对象, 在窗体显示消息的方法
        DGShowMsg dgShow = null;
        //创建一个关闭连接的方法
        DGCloseConn dgCloseConn = null;

        #region 1.0 构造函数
        public MsgConnection(Socket sokMsg, DGShowMsg dgShow, DGCloseConn dgCloseConn)
        {
            this.sokMsg = sokMsg;
            this.dgShow = dgShow;
            this.dgCloseConn = dgCloseConn;
            //创建通信线程,负责调用通信套接字,来接收客户端消息。
            thrMsg = new Thread(ReceiveMsg);
            thrMsg.IsBackground = true;
            thrMsg.Start(this.sokMsg);
        }
        #endregion

        bool isReceive = true;
        #region  2.0 接收客户端发送的消息
        void ReceiveMsg(object obj)
        {
            Socket sockMsg = obj as Socket;
            //3 通信套接字 监听客户端的消息,传输的是byte格式。
            //3.1 开辟了一个 1M 的空间,创建的消息缓存区,接收客户端的消息。
            byte[] arrMsg = new byte[1024 * 1024 * 1];
            try
            {
                while (isReceive)
                {
                    //注意:Receive也会阻断当前的线程。
                    //3.2 接收客户端的消息,并存入消息缓存区。
                    //并 返回 真实接收到的客户端数据的字节长度。
                    int realLength = sockMsg.Receive(arrMsg);
                    //3.3 将接收的消息转成字符串
                    string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg, 0, realLength);
                    //3.4 将消息显示到文本框
                    dgShow(strMsg);
                }
            }
            catch (Exception ex)
            {
                //调用窗体类的关闭移除方法
                dgCloseConn(sokMsg.RemoteEndPoint.ToString());
                //显示消息
                dgShow("客户端断开连接!");
            }
        }
        #endregion

        #region 3.0 向客户端发送文本消息 + void Send(string msg)
        /// <summary>
        /// 3.0 向客户端发送文本消息
        /// </summary>
        /// <param name="msg"></param>
        public void Send(string msg)
        {
            byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(msg);
            //通过指定的套接字将字符串发送到指定的客户端
            try
            {
                sokMsg.Send(MakeNewByte("str",arrMsg));
            }
            catch (Exception ex)
            {
                dgShow("异常" + ex.Message);
            }
        }
        #endregion

        #region 4.0 向客户端发送文件 + void SendFile(string strPath)
        /// <summary>
        /// 4.0 向客户端发送文件
        /// </summary>
        /// <param name="strFilePath"></param>
        public void SendFile(string strFilePath)
        {
            //4.1 读取要发送的文件
            byte[] arrFile = System.IO.File.ReadAllBytes(strFilePath);
            //4.2 向客户端发送文件
            sokMsg.Send(MakeNewByte("file", arrFile));
        }
        #endregion

        #region 4.1 向客户端发送抖屏命令 + void SendShake()
        /// <summary>
        /// 4.1 向客户端发送抖屏命令
        /// </summary>
        public void SendShake()
        {
            sokMsg.Send(new byte[1] { 2 });
        } 
        #endregion

        #region 5.0 返回带标识的新数组 + byte[] MakeNew(string type, byte[] oldArr)
        /// <summary>
        /// 返回带标识的新数组 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="oldArr"></param>
        /// <returns></returns>
        public byte[] MakeNewByte(string type, byte[] oldArr)
        {
            //5.1 创建一个新数组(是原数组长度 +1)
            byte[] newArrFile = new byte[oldArr.Length + 1];
            //5.2 将原数组数据复制到新数组中(从新数组下标为1的位置开始)
            oldArr.CopyTo(newArrFile, 1);
            //5.3 根据内容类型为新数组第一个元素设置标识符号
            switch (type.ToLower())
            {
                case "str":
                    newArrFile[0] = 0;  //只能存0-255之间的数值
                    break;
                case "file":
                    newArrFile[0] = 1;
                    break;
                default:
                    newArrFile[0] = 2;
                    break;
            }
            return newArrFile;
        }
        #endregion

        #region 6.0 关闭通信
        /// <summary>
        /// 关闭通信
        /// </summary>
        public void Close()
        {
            isReceive = false;
            sokMsg.Close();
            sokMsg = null;
        }
        #endregion
    }
}

客户端的是这样的

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

namespace _02聊天室客户端
{
    public partial class FormClient : Form
    {
        public FormClient()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }

        //客户端通信套接字
        Socket sokMsg = null;
        //客户端通信线程
        Thread thrMsg = null;

        #region 1.0 发送连接服务端请求 
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConnectServer_Click(object sender, EventArgs e)
        {
            try
            {
                //1.0创建连接套接字,使用ip4协议,流式传输,tcp链接
                sokMsg = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //2.0获取要链接的服务端节点
                //2.1获取网络节点对象
                IPAddress address = IPAddress.Parse(txtIp.Text);
                IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text));
                //3 向服务端发送链接请求。
                sokMsg.Connect(endPoint);
                ShowMsg("连接服务器成功!");

                //4 开启通信线程
                thrMsg = new Thread(ReceiveMsg);
                thrMsg.IsBackground = true;
                //win7, win8 需要设置客户端通信线程同步设置,才能在接收文件时打开文件选择框
                thrMsg.SetApartmentState(ApartmentState.STA); 
                thrMsg.Start();
            }
            catch (Exception ex)
            {
                ShowMsg("连接服务器失败!" + ex.Message);
            }
        } 
        #endregion

        bool isReceive = true;
        #region 2.0 接收服务端消息
        void ReceiveMsg()
        {
            //准备一个消息缓冲区域
            byte[] arrMsg = new byte[1024 * 1024 * 1];
            try
            {
                while (isReceive)
                {
                    //接收 服务器发来的数据,因为包含了一个标示符,所以内容的真实长度应该-1
                    int realLength = sokMsg.Receive(arrMsg)-1;
                    switch (arrMsg[0])
                    {
                        //文本
                        case 0:
                            GetMsg(arrMsg,realLength);
                            break;
                        //文件
                        case 1:
                            GetFile(arrMsg,realLength);
                            break;
                        default:
                            ShakeWindow();
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                sokMsg.Close();
                sokMsg = null;
                ShowMsg("服务器断开连接!");
            }
        } 
        #endregion
}

服务端需要socket 中的Bind(),Listen(); 客户端需要socket 中的Connect() ;详情见代码;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瓜皮弟子头很铁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值