Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 使用Ada套接字的TCP/IP:如何正确完成数据包?_Sockets_Tcp_Ada_Vnc_Rfb Protocol - Fatal编程技术网

Sockets 使用Ada套接字的TCP/IP:如何正确完成数据包?

Sockets 使用Ada套接字的TCP/IP:如何正确完成数据包?,sockets,tcp,ada,vnc,rfb-protocol,Sockets,Tcp,Ada,Vnc,Rfb Protocol,我试图使用Ada的Sockets库实现远程帧缓冲协议,但在控制发送的数据包长度时遇到了问题 我遵循的是RFC6143specification(),请参见代码中的注释以获取章节编号 -- Section 7.1.1 String'Write (Comms, Protocol_Version); Put_Line ("Server version: '" & Protocol_Version (1 ..

我试图使用Ada的Sockets库实现远程帧缓冲协议,但在控制发送的数据包长度时遇到了问题

我遵循的是
RFC6143
specification(),请参见代码中的注释以获取章节编号

          --  Section 7.1.1
          String'Write (Comms, Protocol_Version);
          Put_Line ("Server version: '"
            & Protocol_Version (1 .. 11) & "'");

          String'Read (Comms, Client_Version);
          Put_Line ("Client version: '"
            & Client_Version (1 .. 11) & "'");

          --  Section 7.1.2
          --  Server sends security types
          U8'Write (Comms, Number_Of_Security_Types);
          U8'Write (Comms, Security_Type_None);


          --  client replies by selecting a security type
          U8'Read (Comms, Client_Requested_Security_Type);
          Put_Line ("Client requested security type: "
            & Client_Requested_Security_Type'Image);

          --  Section 7.1.3
          U32'Write (Comms, Byte_Reverse (Security_Result));

          --  Section 7.3.1
          U8'Read (Comms, Client_Requested_Shared_Flag);
          Put_Line ("Client requested shared flag: "
            & Client_Requested_Shared_Flag'Image);


          Server_Init'Write (Comms, Server_Init_Rec);
问题似乎是(根据wireshark的说法),我对各种
'Write
过程的调用导致字节在套接字上排队而没有被发送

因此,两个或多个数据包作为一个数据包发送,导致数据包格式错误。第7.1.2节和第7.1.3节在一个数据包中连续发送,而不是分成两个

我错误地认为从套接字读取
”会导致输出数据被清除,但事实似乎并非如此

如何告知Ada的Sockets库“此数据包已完成,请立即发送”

取消评论:

我不是协议大师,但根据我自己的经验,对的使用经常被误解

问题似乎是(根据wireshark的说法),我对各种“写入过程”的调用导致字节在套接字上排队而没有被发送

因此,两个或多个数据包作为一个数据包发送,导致数据包格式错误。第7.1.2节和第7.1.3节在一个数据包中连续发送,而不是分成两个

简而言之,TCP不是面向消息的

使用TCP,发送/写入套接字结果只会将数据附加到TCP流。套接字可以在一次或多次交换中自由发送,如果要发送较长的数据,并且要在TCP之上实现面向消息的协议,则可能需要处理消息重建。通常,在消息末尾添加一个特殊的字符序列

进程通过调用TCP并将数据缓冲区作为参数传递来传输数据。TCP将这些缓冲区中的数据打包成段,并调用internet模块将每个段传输到目标TCP。接收TCP将数据段中的数据放入接收用户的缓冲区,并通知接收用户。TCP在其用于确保可靠有序数据传输的段中包含控制信息

另见,引述:

TCP是面向流的连接,而不是面向消息的连接。它没有 信息的概念。当您写出序列化字符串时,它 只能看到无意义的字节序列。TCP可以自由断开 该流向上分为多个片段,它们将在 客户机在这些片段大小的块中。这由你来决定 在另一端重建整个消息

在您的场景中,通常会发送消息长度前缀。 通过这种方式,客户机首先读取长度前缀,这样就可以知道 传入消息应该有多大

或引用:

recv函数只接收1个字节,您可能需要多次调用它才能获得整个有效负载。因此,您需要知道需要多少数据。虽然可以通过关闭连接来表示完成,但这并不是一个好主意

更新:

我还应该提到send函数与recv具有相同的约定:您必须在循环中调用它,因为您不能假设它将发送所有数据。虽然它可能总是在您的开发环境中工作,但这种假设在以后会影响您


禁用Nagle算法,但通常您的期望是错误的。TCP是字节流协议,而不是消息协议。如果您想要消息,您必须自己实现它们。您能否确认读取后字符串
Client\u Version
的长度确实是12?并在从流中读取
Client\u Requested\u Security\u Type
后指出它的值是什么?@DeeDee,是的,Wireshark确认它正好是12个字节,包括“\n”(它在十六进制转储中清晰地显示)。客户机会回复一条同样格式正确的类似消息。在排队等候多个
'Write
调用时,一切都会出错。不,一切都会出错,因为您没有正确阅读。你不能假设一次读取就可以得到一个完整的协议包。它可以提供从一个字节到您提供的缓冲区长度的任何内容,并且该数据可能由一个或多个数据包的一小部分组成,或者同时由这两个数据包组成。你必须在阅读时处理好所有这些。您在发送端所能做的任何事情都不能免除该要求。@user207421。谢谢,我想我现在明白了。我需要为任何“消息”创建足够大的字符缓冲区,并在循环中手动读取(或写入)顺序字节,直到传输正确数量的字符。如果我是用C代码写的,我会本能地做这种事情。Ada包
g-socket.ads
包含了一个关于如何使用TCP和UDP的很好的示例,但是遗憾地忽略了这些缓冲区需要以艰难的方式维护。这表明Ada的
String'Read(stream,stru buffer)
正在阻塞,直到缓冲区已满!不太确定最后一句关于“发送函数”的评论;(a) 它是
sendto()
,不是吗?(b) 对于TCP流,不发送整个消息的唯一原因是一个错误?(TBH粗略复制答案(这是有争议的))@SimonWright不适用于TCP:根据BSD手册页,
send()
write()
@user207421,
sendto()
可以在连接状态下使用(即TCP?),&OP的Ada套接字库可执行此操作。