技术笔记(12)网络数据传输问题

技术笔记(12)网络数据传输问题

  • 希望实现的功能或目标:

    • 解决服务器与客户端进行数据传输时可能会遇到的问题

  • 学习笔记:

    • 粘包半包问题:

      • 是TCP/IP协议中常见的现象,因为TCP发送的数据是连续的字节流,没有固定的边界

      • 粘包:发生在发送方连续发送多个小数据包时,接收方可能会将这些包合并成一个大的数据包来处理。因为TCP为了网络效率,会尽量减少发送次数,所以可能多个小包合并发送

      • 半包:发生在发送方发送的数据包长度大于接收方的缓冲区长度时,接收方无法一次性完整接收整个数据包,导致数据包被分割成多个部分接收。

      • 解决方法:

        • 固定长度:规定好每个数据包统一长度,不足部分用特殊字符填充
        • 分隔符:在相邻数据包之间添加特定字符如&,来区分不同的数据包
        • 长度字段:在数据包的头部添加一个字段来表明数据包的长度,这样接收方就可以根据长度字段来正确的分割和重组数据流
    • 大小端问题:

      • 大端模式:高位字节放在内存的低地址端,低位字节放在内存的高地址端
      • 小端模式:与大端相反,高放高,低放低
      • 大小端问题通常在不同计算架构之间传输数据时需要考虑,例如:网络协议通常使用大端模式,而许多个人计算机则使用小端模式。
      • 即大端模式的网络传输默认高位字节位于低地址,会从低地址开始传输
    • 线程冲突问题:

      • 也称竟态条件,只在多线程程序中,两个以上线程同时访问和修改同一个共享资源而没有适当同步,导致程序执行结果出现不确定性和错误。
      • 解决:通常需要使用互斥锁、信号量或其他同步机制来确保在任何时刻只有一个线程能够访问特定的资源。关键是确保对共享资源的访问在任何时候都是互斥的。
      • 针对于客户端发送信息时,在BeginSend和SendCallback中去操控发送缓冲区各相关变量,可能产生的线程冲突。我们可以通过实现一个消息发送写入队列。然后通过对这个队列上锁来避免,将Send和SendCallback中与消息队列相关的操作都写入锁内。

  • 实现过程中产生的疑惑:

    • 大小端命名的由来?
    • 单个字节和存储单元的内部是否也会有大小端类似的顺序问题?
    • BitConverter. IsLittleEndian的作用?
    • 锁的具体原理?

  • 对疑惑的解答:

    • 命名由来:

      • 源自小说《格列佛游记》中两个派别对于如何正确打开鸡蛋的争论。一方认为应该从鸡蛋的大端开始打开,而另一方则坚持从小端打开。这个比喻被用来描述字节序的概念。
      • 我个人的理解是,鸡蛋往往是一头重,一头轻,如果我们把分量重的那一头比作高位字节,把分量轻的那一头比作低位字节,那么,正立的鸡蛋就是大端模式,因为我们把分量重(高位字节)的部分放在底部(低位地址),而倒立的鸡蛋就是小端模式,即分量轻(低位字节)的部分放在底部(低位地址)。这样一想,还挺生动形象,且也便于个人学习和记忆。
    • 比特没有大小端的问题:

      • 原因:在硬件层面,位(bit)的物理存储顺序通常由CPU的设计决定,对于软件开发者而言是透明不可见的。开发者主要关注的是字节级别的数据表示。
    • BitConverter. IsLittleEndian:

      • 表示当前计算机体系结构字节顺序的静态属性。它的值是只读的,且在运行时确定。
    • 锁:

      • 定义:一种用于控制多线程程序对共享资源的访问的机制。

      • 作用:确保任意时刻,只有一个线程可以访问特定的代码块和资源。

      • 原理:

        • 基本原理是互斥。当一个线程想要访问被锁保护的资源时,它必须首先获得锁。如果锁已经被另一个线程所持有,请求锁的线程就会被阻塞,直到锁被释放。当持有锁的线程完成了对资源的操作后,它会释放锁。
        • 在硬件层面,锁的实现通常依赖于原子操作,即那些在执行过程中不会被其他线程中断的操作。这些原子操作由CPU直接支持,例如现代处理器提供Compare-and-Swap​这样的原子指令,为实现锁的关键。
        • (原子操作:指在多线程环境中,一个或一系列的操作在执行过程中不会被其他线程中断,它们作为一个整体一次性完成,确保数据的一致性和系统的稳定性。这种操作一旦开始,就会运行到结束,中间不会发生任何的上下文切换。另外,能在一个CPU指令中完成而不被中断的操作,也可以认为是原子的。)
      • 类型:

        • 互斥锁:最基本锁类型,保证同一时间只有一个线程可以访问资源
        • 读写锁:允许多个读操作,而写操作会独占锁
        • 自旋锁:让线程在获得锁之前在一个循环中等待,直到锁可用
      • 注意:避免死锁、活锁和资源饥饿等问题

日期:

posted @   静候霜白  阅读(89)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示