首页 » SEO优化 » phpsocketflags技巧_10分钟学会Socket通讯学不会你打我

phpsocketflags技巧_10分钟学会Socket通讯学不会你打我

duote123 2024-12-08 0

扫一扫用手机浏览

文章目录 [+]

在我的职业生涯中,有且仅用过一次UDP通讯。
而TCP通讯系统却常常写,恰好本日写了一个TCP通讯的软件。
总结一下内容

软件利用C#编程缘故原由写的,为了能够利用所有的电脑,采取了NET Framework 4.0。

phpsocketflags技巧_10分钟学会Socket通讯学不会你打我

启动做事端

做事端启动的时候,先写一个Task任务启动一个做事真个链接,把稳做事真个ip,最好设置为0.0.0.0,这样所有的客户端都可以通过做事器ip地址链接到做事端。

phpsocketflags技巧_10分钟学会Socket通讯学不会你打我
(图片来自网络侵删)

Task.Factory.StartNew(() =>{ Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); EndPoint point = new IPEndPoint(IPAddress.Parse(ip), port); server.Bind(point); server.Listen(1000); while (true) { Socket client = server.Accept(); }}

做事端会启动一个无限循环的while,在这个循环中,通过Accept方法不断的吸收链接的客户端。

吸收客户端

在这个循环里面可以记录一下客户真个信息,并启动另一个Task任务,去接管客户端给做事端发送的。

Task.Factory.StartNew(() =>{ while (true) { byte[] buffer = new byte[1024]; if (!client.Connected) { break; } int cnt = 0; try { cnt = client.Receive(buffer); if (cnt <= 0) { Thread.Sleep(1000); continue; } } catch (Exception ex) { break; } //由于buffer数组是1024长度,如果实际数据长度小于1024 则会涌现0x00的空缺数据,须要删除,只保留有效数据 List<byte> lstBuffer = new List<byte>(); for (int i = buffer.Length - 1; i >= 0; i--) { if (buffer[i] == 0x00 && lstBuffer.Count<=0) continue; lstBuffer.Insert(0, buffer[i]); } //吸收到的 Business.queueReceiver.Enqueue(new Tuple<string, byte[]>(pointClient.ToString(), lstBuffer.ToArray<byte>())); ReceiveCount += 1; }});

对付做事端来说,任何一个链接到做事真个客户端,在做事端都该当启动一个Task去实时吸收客户真个。

而由于客户端有可能会随时关闭或者断开,以是对Receive方法加非常判断,防止由于某一次的吸收非常造成Task任务过期关闭。

对付做事端,一旦创造客户真个没有吸收成功,或者判断到客户端已经断开,则可以推出while循环,然后关闭Task任务,结束与客户真个链接。

业务逻辑处理

对付任何项目的Socket通讯软件,都会有干系的通信协议,对照业务干系的通信协议和上面吸收的客户端信息对业务逻辑进行处理即可。

业务处理须要,如果数据量比较小,则正常处理即可。

如果业务量大,并发大,数据量大等则须要考虑粘包的问题。

为了后期方面查讯问题,须要对所有吸收和处理的数据做日志处理,在处理日志时,如果有redis最好,如果没有,建议日志信息写入自己定义的行列步队中(比如:ConcurrentQueue),不建议直接写入文件或者数据库,这样会造成数据处理的效率缓慢。

为了使业务处理的逻辑不影响正常的客户端和做事真个通讯,建议对业务处理在其他的Task任务中进行处理。
这样可以担保客户端和做事端之间吸收和发送的通道正常。

对客户端发送

对付所有链接到做事真个客户端,都该当对客户端进行记录,并在新的Task任务中,分别对做事端须要发送的信息进行发送。
这样就可以担保发送的统一性,在一个任务中进行发送,方便数据掌握。

由于客户端数量不知道,以是发送的时候,把须要发送的放入行列步队中,然后在行列步队有的时候在进行异步发送。
只要发送行列步队中有,则不须要对发送任务进行停息掌握,担保及时有效。

Task.Factory.StartNew(() =>{ while (true) { try { if (Business.queueSender.IsEmpty) { Thread.Sleep(1000); continue; } Business.queueSender.TryDequeue(out Tuple<string, byte[]> tuple); if (tuple == null) continue; Socket client = Business.dicClient[tuple.Item1]; if (!client.Connected) { Business.dicClient.TryRemove(tuple.Item1, out Socket outSocket); continue; } List<byte> buffer = new List<byte>(); client_name = tuple.Item1; buffer.AddRange(tuple.Item2); client.BeginSend(buffer.ToArray(), 0, buffer.Count, SocketFlags.None, SendCallback, new Object[] { tuple, client, buffer }); Thread.Sleep(1); }catch (Exception ex) { } }});业务数据入库

在通讯稳定的情形下,如果没有redis缓存等,建议把须要写入数据库的数据也放入行列步队中,每隔一段韶光进行保存。
而不要实时保存,数据库的写入须要更多的IO,放到一个Task任务中进行处理,可以担保数据保存的同等性。

Task.Factory.StartNew(() =>{ while (true) { string[] tablenames = Business.dicSaveData.Keys.ToArray(); foreach (string table in tablenames) { if (Business.dicSaveData[table].IsEmpty) { continue; } var datas= Business.GetDataFromQueue(table); DataTable dt = DicToTable(table, datas); DbAccess.BatchAdd(table, dt,DbAccess.log_connectionstring); } Thread.Sleep(30000); }});日志处理

所有的都须要履行显示在系统上,并供用户查询,定位问题。
而在CS软件中,如果对界面控件进行操作,就要进入主线程。
主线程的频繁操作或者大数据量处理、显示,会造成系统卡顿。
影响全体系统的性能。

日志处理也放到一个Task任务中,并定时清空系统软件的界面显示的数据

对付日志信息,也要进行物理保存。
在日志信息达到一定的数量,或者达到一段韶光后,可以把日志信息保存到文本中。

Task.Factory.StartNew(() =>{ List<string> msgs = new List<string>(); while (true) { if (Business.queueMsg.IsEmpty) { Thread.Sleep(1000); continue; } while (!Business.queueMsg.IsEmpty) { if (msgs.Count > 1000) { break; } Business.queueMsg.TryDequeue(out string msg); if (string.IsNullOrEmpty(msg)) continue; msgs.Add(msg); } try { string file = $"{logdir}/{DateTime.Now.ToString("yyyyMMddHH")}.txt"; string data = string.Join("\r\n", msgs); using (StreamWriter writer = new StreamWriter(file, true, Encoding.Default)) { writer.WriteLine(data); } msgs.Clear(); } catch (Exception ex) { Business.AddFailLogs($"写日志失落败,缺点描述:{ex.Message}"); } if (Business.queueMsg.Count > 1000) { Thread.Sleep(10); continue; } Thread.Sleep(10000); }});行列步队处理

在全体业务逻辑过程中,利用了大量的行列步队,字典等,须要在软件的界面上显示行列步队的数量或者字典的详细信息。

说一个碰到的问题:

刚开始写的时候,由于链接的客户端比较少,以是日志的数量比较少,很快就写入数据库了,后来随着客户真个增多,日志的数量翻倍的增加,创造问题后,查询日志竟然找不到。

后来,把日志行列步队的数量显示在界面上,创造所有的客户端设备上线后,竟然在内存中有5万条日志信息。
处理特殊缓慢。

客户端测试

在写完做事端后,须要写一个客户端进行所有的协议测试。
根据协议文档,在客户端发送干系协议,并网络做事端返回的信息。

客户端测试,可以写单客户端测试,也可以写多客户端测试,通过在软件上定义多个Task任务,分别启动多个客户端进行压力测试和并发测试。

总结

在全体软件的编码过程中,碰到的问题包括

大端小真个数据处理问题协议文档对接过程中对付字节的定义和编码问题怎么担保做事端软件持续在线。
在前期的测试中,创造有的时候做事端显斧正常,但是常常不返回,便是由于客户端断开后,做事真个Task关闭了,造成做事端对应的客户端没有反馈。
常常须要与各种设备进行协议对接和修正验证。
常常须要给设备端查看干系的协议过程,这便是日志的功劳了利用Task作业进行异步编程,可以提高软件的利用效率,防止软件涌现未相应的情形。

末了

写了这么多年的软件,写过委托处理、多线程处理、Task作业、并行编程、异步编程。

虽然技能发展的很快,业务处理的性能得到的极大的提升。
但是看到现在的大数据处理,觉得还得靠提升硬件性能和网络带宽来提升性能。

说一个有趣的事情:

以前写过一个做事端软件,须要吸收1000个客户端软件持续发送的大量数据。
当时做事端放到了阿里云上,怎么测试都是弗成。
后来在登录做事器看了看,CPU一贯100%。
内存倒是不多。

你猜末了怎么办理的,客户把阿里云的CPU提升到128核,CPU立时降到2%。

技能办理性能问题到末了都要钞能力

相关文章