你好。我是一个网络类,我们正在使用我们迄今为止在课堂上学到的套接字函数创建自己的“网络API”。
对于作业,教授提供了已经完整的聊天和服务器程序,我们要填写一个空白的.c文件,该文件有一个相关的头文件,描述了我们的小“网络API”中的函数调用,即聊天和服务器使用的程序。
我已接近完成但遇到了问题。我会进去搞乱我的代码,但是我的“网络API”的所有其他部分都工作,所以当我如此接近完成并且稍微改变导致其他部分没有时,我不想搞砸它上班。另外,我并非100%确定我确实知道我的错误是什么。
我的问题是我的函数recv_line应该模仿recv()。
我的函数recv_line从客户端获取文件描述符,用于与服务器建立的连接。然后我继续使用fdopen将流与文件描述符相关联。代码如下:
// Associate a stream with the sock_fd
if (NULL == (fdstream = fdopen(sock_fd, "r"))) {
return -1;
}
现在这是我相信我的错误的地方,但正如我所说,我不是100%肯定。首先,我第一次使用我的recv_line函数时效果很好。事实上它确实按预期方式对行进行了recv_line。但问题出现了第二次。
我使用GDB完成了我的功能,上面的代码确实执行没有问题。然后我继续从我的流中剥离一个字符(使用fgetc)并检查它是否等于EOF字符。如果是我返回,否则我会处理它。我第二次调用recv_line它返回cuse,每次都读取EOF字符。
我假设发生了这种情况,因为发送到客户端的数据是在原始流(第一次创建的数据)中,第二次调用fdopen时,我创建的第二个流中没有任何数据?当我第二次打电话给我时,我不完全确定fdopen是如何工作的?
在我看来,我以这种方式阅读我的数据,因为我们应该继续读取数据,直到我们读取EOF或字符序列\ r \ n。我在流中使用getc和ungetc来提供一个预检机制,用于检查EOF或\ r \ n序列。
所以尽管如此,有没有人知道我的代码和程序到底发生了什么?我用Google搜索一个方法来检查FD是否有一个关联的流,并且没有成功找到/看到任何东西。我做了一些研究,看看是否有一些fstat时间功能,让我看到相关的蒸汽,并没有任何结果。我可以复制传入函数recv_line的FD,然后复制FD上的fdopen并避免所有这些问题吗?
感谢所有帮助。如果我不够清楚,我很抱歉。如果你要求我这样做,我会尽力澄清任何事情。抱歉,我的问题太长了。 = *(
再次感谢。我非常感谢你的帮助。
答案 0 :(得分:2)
这是来自fdopen
手册页:
fdopen()函数将流与现有文件相关联 描述符,fd。流的模式(值“r”,“r +”之一, “w”,“w +”,“a”,“a +”)必须与文件的模式兼容 描述。新流的文件位置指示器设置为 属于fd,错误和文件结束指标 清除。模式“w”或“w +”不会导致文件截断。的的 文件描述符没有重复,并且当fdopen()创建的流关闭时将关闭。 [emph。矿]
换句话说,正如我所理解的那样(这不是我的专业领域),你一遍又一遍地“劫持”套接字文件描述符的想法实际上是问题,因为当你完成了它是第一次,你不仅关闭你的流,而且还关闭套接字连接。
答案 1 :(得分:2)
我假设发生了这种情况,因为发送到客户端的数据是在原始流(第一次创建的数据)中,第二次调用fdopen时没有任何数据
的文件描述符第二个流读取我创建了?
这非常正确(有一些小修正)。流对象的主要职责是从内核读取文件描述符数据流到用户区,这样您就不需要系统调用的开销。但是一旦流对象读取数据流,内核就会使它的'读指针'前进,所以下次当你尝试从文件描述符中读取数据时,它就会从你离开的地方开始。
您只能为给定的描述符调用fdopen 一次。如果您可以重新构建代码,以便有一个地方可以轻松调用fdopen一次,那么就可以了。
一旦你调用了fdopen,你就不应再对文件描述符做任何事情了 - 甚至不关闭它(当你调用fclose时,底层描述符将被关闭)。
根据Jonathon Leffler的评论,我猜教授的代码也将关闭描述符。如果是这样,则不能使用fdopen。
一些想法:
根据评论进行更新
@Chris - 让我解释一下使用fdopen的风险。在文件描述符上使用fdopen之后,必须调用fclose (或者冒着泄漏为FILE分配的资源*的风险),并且无法在描述符上调用close (因为fclose描述符可能会遇到多次关闭描述符的问题)。因此,除非你的代码已被委派了关闭描述符的责任(在这种情况下你可以调用fclose),你不能使用fdopen。
没有内置方法来检测是否已在描述符上调用fdopen。您需要自己添加逻辑。你需要保留fdopen返回的FILE *的集合;如果你已经有一个给定描述符的FILE *,你会使用它,否则你会调用fdopen。
答案 2 :(得分:1)
我不确定我是否真的理解你的问题,但我建议在创建套接字时直接打开输入/输出流,只要套接字有效,就将它们与套接字一起保存在结构中(连接的)。这样您就不需要为每一行打开新的流。然后recv_line
函数将输入流作为参数而不是套接字。