我正在使用C和Linux平台上的客户端 - 服务器应用程序。我想要实现的是在客户端和服务器上通过TCP连接更改套接字ID,而不会丢失数据,客户端将数据从文件发送到主线程中的服务器。应用程序是多线程的,其他线程根据设置的某些全局标志更改套接字ID。
问题:应用程序在IPv4和IPv6路径上建立了两个TCP套接字连接。我首先在主线程中通过TCP-IPv4连接传输文件。另一个线程正在检查某些全局标志,并且可以访问/共享为主线程中的每个协议创建的套接字ID。 send和recv在其调用中使用指针变量指向要用于数据传输的套接字ID。数据最初通过TCP-Ipv4传输。一旦设置了全局标志并且进行了很少的其他检查,则另一个线程将发送调用中使用的套接字ID更改为指向IPv6套接字。此线程还负责在两个主机之间传递更改。我在切换之前完全通过IPv4发送所有数据。此外,我刚刚切换套接字ID后通过Ipv6发送数据。但是在传输过程中,IPv6连接会丢失数据。(我在服务器端send(*p_dataSocket.socket_id,sentence,p_size,0);
的send函数中使用指针变量来动态更改指向IPv6套接字ID的指针)
分别在两侧的recv和send调用之后的错误是ESPIPE:Illegal seek
,但是这个错误甚至在切换之前就存在了。所以我非常确定这与数据丢失无关
我正在使用pselect()
来检查每个套接字的可用数据。我可以以某种方式理解切换时的数据丢失(如果处理不当),但我无法弄清楚切换后传输过程中数据丢失的原因。我希望我清楚问题是什么。我还检查过每个协议单独发送数据而不切换,没有数据丢失。我最初通过Ipv6传输数据,然后切换到IPv4,没有数据丢失。除了使用errno
或netstat
之外,我们非常希望了解如何调查此问题。
答案 0 :(得分:1)
当您使用TCP发送数据时,您无法在之间丢失部分信息。您可以按发送方式接收字节流,也可以根本不接收任何内容:只要您正确使用与套接字相关的功能。
您可能需要调查几点。
首先,您必须确保您确实发送了丢失的数据。在服务器端应用程序上添加一些日志记录:将您发送的任何内容(如果send()转储到某个文件中)。还包括一些额外信息,例如:
数据包编号== 1234,* p_dataSocket.socket_id == 11,数据==“data_contents_here”,总共22个字节; send()return == 22
这里重要的是观看*p_dataSocket.socket_id
的内容。确保您使用互斥锁或其他类似的东西导致您有一个定期读取socket_id
内容的线程和另一个偶尔会更改它的线程。除非您的线程在读/写时拥有垄断权限,否则您无需担心从该地址获取错误的值。对于正常的程序操作和调试信息的生成都很重要。
此处另一个可能的问题是选择sentence
发送的逻辑。在多线程程序中,可能难以跟踪此变量的损坏。传输信息的记录也会对您有所帮助。
使用任何TCP嗅探器来检查TCP堆栈实际传输的内容。是否有丢失数据的数据包?如果没有这些数据包,请尝试找出哪个send()调用负责发送该数据。如果存在这些数据包,请检查接收方是否存在错误。
errno
值不应单独使用。只有当你从函数中得到错误的返回时,它的值才有意义。尝试找出确切的errno何时成为ESPIPE当任何API函数返回-1
之类的东西(取决于函数)时,可能会发生这种情况。当你发现它发生的地方时,你应该找出那段特定代码中的错误(调试器是你的朋友)。请记住,多线程环境中的errno
行为取决于您的系统实现。确保使用-pthread
选项(gcc)或至少使用-D_REENTRANT编译以最小化风险。
使用errno == ESPIPE检查this question以获取有关您的情况可能原因的一些信息。尝试一些调试技术,如那里所建议的那样。 ESPIPE的Errno值提示您在程序中的某处错误地使用了文件描述符。也许某个地方你正在使用套接字 fd 作为常规文件或类似的东西。这可能是由某些竞争条件引起的(从多个线程同时访问一个对象)。