socket 客户端 的一些想法
-----------------包头--------------------------
4byte 4byte 2byte 2byte
数据长 数据长 约定数字 0
------------------------------------------------
1.登录
2.每隔15秒发送心跳包
3.死循环接收数据,把收到的byte[]塞到List<byte>(队列,先进先出)(生产者)
4.List<byte> 要有同步锁
5.死循环读取List<byte>,把数据解析出来(消费者)(可以多消费者)
----------------------------------2017/3/22 更新------------------------------------------------------
感觉好慢,不能即时展现数据
1.心跳包
1 #region 服务器心跳连接 2 3 private static readonly System.DateTime Jan1st1970 = new System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc); 4 5 /// <summary> 6 /// 服务器心跳连接 7 /// </summary> 8 public void keepAlive() 9 { 10 while (readyFlag) 11 { 12 //获取与弹幕服务器保持心跳的请求数据包 按照需求生成心跳包并转成byte[] 13 byte[] keepAliveRequest = DyMessage.getKeepAliveData((int)(((long)(System.DateTime.UtcNow - Jan1st1970).TotalMilliseconds) / 1000)); 14 15 try 16 { 17 //向弹幕服务器发送心跳请求数据包 18 bos.Write(keepAliveRequest, 0, keepAliveRequest.Length); 19 bos.Flush(); 20 //sendToText("exMsg","发送心跳包成功!"); 21 22 //设置间隔45秒再发送心跳协议 23 Thread.Sleep(45000); //keep live at least once per minute 24 25 } 26 catch (Exception e) 27 { 28 //e.printStackTrace(); 29 sendToText("exMsg", "错误:发送心跳包失败!"); 30 readyFlag = false; 31 } 32 } 33 } 34 #endregion
2.接受数据
1 #region 新获取弹幕 2 3 //缓存池 4 private List<byte> list = new List<byte>(); 5 //同步锁 6 private object myLock = new object(); 7 private Semaphore TaskSemaphore = new Semaphore(0, 256); 8 9 //解析数据 10 public void KeepRead(object data) 11 { 12 //int Index = (int)data; 13 14 while (readyFlag)//死循环 15 { 16 TaskSemaphore.WaitOne();//等待 17 string dataStr = ""; 18 lock (myLock)//同步锁 19 { 20 if (list.Count > 12)//12个长度的包头 21 { 22 byte[] topBytes = list.Take(12).ToArray();//拿出包头 23 24 byte[] packSizeBuffer1 = new byte[4];//4 字节小端整数,表示整条消息(包括自身)长度(字节数)。 25 Array.Copy(topBytes, 0, packSizeBuffer1, 0, 4);//消息长度 26 int packSize1 = BitConverter.ToInt32(packSizeBuffer1, 0);//转成长度 27 28 byte[] packSizeBuffer2 = new byte[4];//4 字节小端整数,表示整条消息(包括自身)长度(字节数)。 29 Array.Copy(topBytes, 4, packSizeBuffer2, 0, 4);//消息长度 30 int packSize2 = BitConverter.ToInt32(packSizeBuffer2, 0);//转成长度 31 32 byte[] packTypeBuffer = new byte[4];//4 字节小端整数,表示整条消息(包括自身)长度(字节数)。 33 Array.Copy(topBytes, 8, packTypeBuffer, 0, 2);//消息长度 34 int packType = BitConverter.ToInt32(packTypeBuffer, 0);//转成长度 35 36 if (packSize1 == packSize2 && packType == DY_MESSAGE_TYPE_SERVER)//根据需求验证包头 37 { 38 int packSize = packSize1 + 4;//一个包长度 = 包头长+数据长 39 40 if (list.Count >= packSize)//如果缓存数据够一个包的长度 41 { 42 byte[] totalBytes = list.Take(packSize).ToArray();//拿到一个包的数据 43 //Console.WriteLine("截取数据:" + Newtonsoft.Json.JsonConvert.SerializeObject(totalBytes)); 44 45 list.RemoveRange(0, packSize);//取出后删除 46 //Console.WriteLine("截取后源数据:" + Newtonsoft.Json.JsonConvert.SerializeObject(list)); 47 48 dataStr = Encoding.UTF8.GetString(totalBytes, 12, totalBytes.Length - 12);//包的数据转换成string 49 //Console.WriteLine("截取数据输出:" + dataStr); 50 51 //对单一数据包进行解析 52 MsgView msgView1 = new MsgView(dataStr); 53 //分析该包的数据类型,以及根据需要进行业务操作 54 parseServerMsg(msgView1.getMessageList()); 55 56 //Console.WriteLine(Index + ""); 57 } 58 } 59 } 60 } 61 } 62 } 63 64 public void KeepMsgToList() 65 { 66 while (readyFlag) 67 { 68 if (client == null || !client.Connected)//如果tcpclient为null或断开连接 69 { 70 break; 71 } 72 else 73 { 74 try 75 { 76 byte[] bytes = new byte[client.ReceiveBufferSize]; 77 int readSize = m_Reader.Read(bytes, 0, (int)client.ReceiveBufferSize);//读取数据 78 if (readSize > 0)//说明是有读到数据的 79 { 80 byte[] totalBytes = new byte[readSize];//C#神器,byte[]会自动延长 81 Array.Copy(bytes, 0, totalBytes, 0, readSize);//消息长度 82 //totalBytes = totalBytes.Concat(bytes).ToArray();//C#神器,byte[]会自动延长 83 lock (myLock)//同步锁 84 { 85 list.AddRange(totalBytes);//把数据加到List<byte>中 先进先出 86 } 87 TaskSemaphore.Release(1); // 每添加一个任务,信号量加1 88 } 89 } 90 catch (Exception e) 91 { 92 if (client == null || client.Connected == false) 93 { 94 shutdown();//注销登录,断开连接,readyFlag=false 等操作 95 sendToText("exMsg", "尝试重新连接!"); 96 } 97 else 98 { 99 sendToText("exMsg", "错误:获取弹幕失败!"); 100 } 101 } 102 } 103 } 104 } 105 106 #endregion
启动线程
1 //保持弹幕服务器心跳 2 //KeepAlive alive = new KeepAlive(); 3 keepAlive = new Thread(new ThreadStart(danmuClient.keepAlive)); 4 keepAlive.IsBackground = true; 5 keepAlive.Start(); 6 //AddTalkMessage("开始发送心跳包! "); 7 8 //获取弹幕服务器发送的所有信息 9 //KeepGetMsg msg = new KeepGetMsg(); 10 keepGetMsg = new Thread(new ThreadStart(danmuClient.KeepMsgToList)); 11 keepGetMsg.IsBackground = true; 12 keepGetMsg.Start(); 13 //AddTalkMessage("开始获取弹幕! "); 14 15 //解析信息 16 for (int i = 0; i < 10; i++) 17 { 18 Thread keepReadMsg = new Thread(new ParameterizedThreadStart(danmuClient.KeepRead)); 19 keepReadMsg.IsBackground = true; 20 keepReadMsg.Start(i); 21 }
-----------------------------修改----------------------------------------
1 public void KeepMsgToString() 2 { 3 while (readyFlag) 4 { 5 if (client == null || !client.Connected) 6 { 7 break; 8 } 9 else //if (ntwStream.DataAvailable)//说明是有读到数据的 10 { 11 try 12 { 13 byte[] bytes = new byte[client.ReceiveBufferSize]; 14 int readSize = m_Reader.Read(bytes, 0, (int)client.ReceiveBufferSize); 15 if (readSize > 0)//说明是有读到数据的 16 { 17 byte[] totalBytes = new byte[readSize];//C#神器,byte[]会自动延长 18 Array.Copy(bytes, 0, totalBytes, 0, readSize);//消息长度 19 list.AddRange(totalBytes); 20 21 //获取数据完成,开始解析 22 23 string dataStr = ""; 24 while (list.Count > 12) 25 { 26 byte[] topBytes = list.Take(12).ToArray(); 27 28 byte[] packSizeBuffer1 = new byte[4];//4 字节小端整数,表示整条消息(包括自身)长度(字节数)。 29 Array.Copy(topBytes, 0, packSizeBuffer1, 0, 4);//消息长度 30 int packSize1 = BitConverter.ToInt32(packSizeBuffer1, 0);//转成长度 31 32 byte[] packSizeBuffer2 = new byte[4];//4 字节小端整数,表示整条消息(包括自身)长度(字节数)。 33 Array.Copy(topBytes, 4, packSizeBuffer2, 0, 4);//消息长度 34 int packSize2 = BitConverter.ToInt32(packSizeBuffer2, 0);//转成长度 35 36 byte[] packTypeBuffer = new byte[4];//4 字节小端整数,表示整条消息(包括自身)长度(字节数)。 37 Array.Copy(topBytes, 8, packTypeBuffer, 0, 2);//消息长度 38 int packType = BitConverter.ToInt32(packTypeBuffer, 0);//转成长度 39 40 if (packSize1 == packSize2 && packType == DY_MESSAGE_TYPE_SERVER) 41 { 42 int packSize = packSize1 + 4;//一个包长度 43 44 if (list.Count >= packSize) 45 { 46 byte[] totalBytes1 = list.Take(packSize).ToArray(); 47 //Console.WriteLine("截取数据:" + Newtonsoft.Json.JsonConvert.SerializeObject(totalBytes)); 48 49 list.RemoveRange(0, packSize);//取出后删除 50 //Console.WriteLine("截取后源数据:" + Newtonsoft.Json.JsonConvert.SerializeObject(list)); 51 52 dataStr = Encoding.UTF8.GetString(totalBytes1, 12, totalBytes1.Length - 12); 53 //Console.WriteLine("截取数据输出:" + dataStr); 54 55 //对单一数据包进行解析 56 MsgView msgView1 = new MsgView(dataStr); 57 //分析该包的数据类型,以及根据需要进行业务操作 58 parseServerMsg(msgView1.getMessageList()); 59 60 } 61 else 62 { 63 break; 64 } 65 } 66 } 67 68 } 69 } 70 catch (Exception e) 71 { 72 if (client == null || client.Connected == false) 73 { 74 shutdown(); 75 sendToText("exMsg", "尝试重新连接!"); 76 } 77 else 78 { 79 sendToText("exMsg", "错误:获取弹幕失败!"); 80 } 81 } 82 } 83 } 84 }