简单的socket实例及原理(含源码)

1 篇文章 0 订阅

什么是socket?

所谓socket通常也称作"套接字",用于描述IP地址bai和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

 

socket连接过程:

socket分为服务端及客户端,这里我们用serverSocket及clientSocket分别表示

服务器监听:服务器端socket并不主动指定的客户端socket,而是处于等待监听状态,实时监控网络状态。

客户端请求:客户端clientSocket发送连接请求,目标是服务器的serverSocket。所以clientSocket必须知道serverSocket的ip及端口号

连接确认:当服务器socket监听到或者是受到客户端socket的连接请求时,服务器就响应客户端的请求,建议一个新的socket,把服务器socket发送给客户端,一旦客户端确认连接,则连接建立。

 

下图简单说明链接过程:

 

具体可以参考简易代码(这里源码已放入“墨水直达”公众号,回复socket源码即可):

源码为wpf,因为项目源码不好拆分,且不好打包,所以建了个实例,这里看不太明白的可以下载源码好好研究下

//服务端

 Thread threadWatch = null;
 Socket Mysocket = null;
 ListBox ClientListboxs = null;
 //接受缓存
  byte[] arrMsgRec = new byte[1024 * 1024 * 2];
 Socket policy = null;
 Dictionary<string, Socket> SoketList = new Dictionary<string, Socket>();
 Thread threadRece = null;
   private void StartSocket()
        {
            //创建监听套接字
            Mysocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //获取ip对象
            IPAddress address = IPAddress.Parse("192.168.3.57");
            //创建IP和端口
            IPEndPoint endpoint = new IPEndPoint(address, int.Parse("4502"));
            Mysocket.Bind(endpoint);//绑定EndPoint对像 
            //监听队列长度
            Mysocket.Listen(10);
            threadWatch = new Thread(WatchConnection);
            threadWatch.IsBackground = true;
            threadWatch.Start();
        }
        
   // 监听新客户端请求    
 private void WatchConnection()
        {
            showMessage("等待客户连接");
            while (true)
            {
                policy = Mysocket.Accept();
                Socket policynew = policy;
                showMessage("连接成功");

                ListBox ClientListbox = ClientListboxs;
                ClientListbox.Dispatcher.Invoke(new Action(() => { ClientListbox.Items.Add(policynew.RemoteEndPoint.ToString()); }));
                SoketList.Add(policynew.RemoteEndPoint.ToString(), policy);//为新建连接创建新的socket
                if (threadRece == null)
                {
                    threadRece = new Thread(Rece);
                    threadRece.IsBackground = true;
                    threadRece.Start();
                }
            }
        }

这个线程是一直存在的,主要的任务就是监听是否有Client与Server端进行连接,如果连接成功则会另开一个线程”Rece”。在该线程中则主要是得到字符数据的处理,包括接受数据以及发送数据。

  private void Rece()
        {
            while (true)
            {
                try
                {
                    int strlong = policy.Receive(arrMsgRec);
                    byte[] message = arrMsgRec;
                    byte[] lin = arrMsgRec.Skip(2).Take(strlong - 4).ToArray();
                    string strMsgRec = System.Text.Encoding.UTF8.GetString(lin, 0, strlong - 4);//实际转换的字节长度为内容长度
                    showMessage(strMsgRec);
                }
                catch (Exception)
                {
                    
                }
            }
        }

        private void showMessage(string msg)
        {
            Action action = () => MsgContent.AppendText(msg + "\r\n");
            if (System.Threading.Thread.CurrentThread !=
        MsgContent.Dispatcher.Thread)
            {
                MsgContent.Dispatcher.Invoke
                    (System.Windows.Threading.DispatcherPriority.Normal,
                    action);
            }
            else
            {
                action();
            }
        }

下面是向客户端发送数据

 private void send(object sender, RoutedEventArgs e)
        {
            senddate = System.DateTime.Now;
            var TELH = (char)0x02 + (char)0x30;//头部(无需照搬,测试用的)
            var TELF = (char)0x5F + (char)0x03;//尾部(无需照搬,测试用的)
            var Content = MsgContext.Text;
            var msg = TELH + Content + TELF;
            byte[] btMsg = System.Text.Encoding.UTF8.GetBytes(msg);
            policy.Send(btMsg);
            showMessage("发送:" +  MsgContext.Text);
        }

 这里需要注意:其实在TCP/IP传输的数据都应该是以字节为单位的。比如说传送50个double类型的数据就是传送400个字节的数组

//客户端

Socket Mysocket = null;
byte[] arrMsgRec = new byte[1024 * 1024 * 2];
   public void client()
        {
            Mysocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //获取ip对象
            IPAddress address = IPAddress.Parse("192.168.3.57");
            //创建IP和端口
            IPEndPoint endpoint = new IPEndPoint(address, int.Parse("4502"));
            Mysocket.Connect(endpoint);
            Thread threadWatch = new Thread(ReceiveMsg);
            //threadWatch.IsBackground = true;
            threadWatch.Start();
        }

从服务端源码可以看到消息的组成由头部(两字节)+内容+尾部(两字节)组成,所以这里取内容的话跳过头部取总长度-4的部分就好了

 public void ReceiveMsg()
        {
            while (true)
            {
                int strlong = Mysocket.Receive(arrMsgRec);
                byte[] message = arrMsgRec;
                byte[] lin = arrMsgRec.Skip(2).Take(strlong - 4).ToArray();
                string strMsgRec = System.Text.Encoding.UTF8.GetString(lin, 0, strlong - 4);//实际转换的字节长度为内容长度
                showMessage(strMsgRec);
            }
        }

//发送

 public void Sends()
        {
           
            var TELH = (char)0x02 + (char)0x30;//头部
            var  TELF = (char)0x5F + (char)0x03;//尾部
            var Content = MsgSend.Text;
            var msg = TELH + Content + TELF;
            byte[] btMsg = System.Text.Encoding.UTF8.GetBytes(msg);
            Mysocket.Send(btMsg);
            showMessage("发送:" + MsgSend.Text);

        }

将数据显示在控件上

 private void showMessage(string msg)
        {
            Action action = () => MsgContent.AppendText(msg + "\r\n");
            if (System.Threading.Thread.CurrentThread !=
        MsgContent.Dispatcher.Thread)
            {
                MsgContent.Dispatcher.Invoke
                (System.Windows.Threading.DispatcherPriority.Normal,
                action);
            }
            else
            {
                action();
            }

        }

 这里,简单的一个socket通讯就完成了,效果如下:

socket的实际用处有很多,这里我主要用于程序和设备进行通讯,像qq就是用socket通信的,浏览器和服务器也是用socket进行通信的,只是传输的是以http协议的http报文, 有兴趣的朋友可以自己研究下

这里推荐一篇比价详细的博文http://www.jytek.com/seesharpsocket

有兴趣的可以关注“墨水直达”,里面有许多免费的编程资料可以领取哦~

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值