C++ 在使用Poll()的TCP服务器-客户端连接中,是否需要手动设置事件?我从来不会伸手去给插座写东西
我在一个fd上使用poll()在c中的客户端和服务器之间建立了连接。我希望客户端在服务器有东西要发送时接收消息,反之亦然 据我所知,poll()侦听文件描述器上的事件。我不清楚这些事件(或复仇者)是如何触发的,以确定何时在fd上发送或接收 我曾尝试在客户端的循环中使用读写(或发送和接收),但它们会阻塞,所以我也切换到了客户端的poll() 在客户端,我永远不会使用C++ 在使用Poll()的TCP服务器-客户端连接中,是否需要手动设置事件?我从来不会伸手去给插座写东西,c++,c,sockets,networking,C++,C,Sockets,Networking,我在一个fd上使用poll()在c中的客户端和服务器之间建立了连接。我希望客户端在服务器有东西要发送时接收消息,反之亦然 据我所知,poll()侦听文件描述器上的事件。我不清楚这些事件(或复仇者)是如何触发的,以确定何时在fd上发送或接收 我曾尝试在客户端的循环中使用读写(或发送和接收),但它们会阻塞,所以我也切换到了客户端的poll() 在客户端,我永远不会使用}else if(fds[0].revents&POLLOUT)部分,这意味着套接字永远无法写入 //Create - bind
}else if(fds[0].revents&POLLOUT)
部分,这意味着套接字永远无法写入
//Create - bind - listen to a socket named listeningSocket
struct pollfd fds[1];
fds[0].fd = listeningSocket;
fds[0].events = POLLIN | POLLPRI;
if (poll(fds, 1, 3000)) {
(client_sock = accept(listeningSocket, &client, (socklen_t *) &c));
spdlog::info("Connection accepted");
std::thread thread(&ConnectionHandler::Handle, std::ref(requestHandler), client_sock);
thread.detach();
}
客户端块
while (true) {
if ((rv = poll(fds, 1, 100) > 0)) {
if (fds[0].revents & POLLIN ){
recv(sockfd, buff, 200, 0);
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));
}
}else if (fds[0].revents & POLLOUT){
puts(buff);
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, sizeof(buff));
break;
}
}
连接时,服务器向客户端发送一条带有write()
的欢迎消息。客户机recv()
s这一点,但之后再也不会转向右回到服务器
我错过什么了吗?当套接字上没有要接收的延迟数据时,它不应该准备好写入吗?在
之前删除}
,如果,则删除。
然后将其放在else if
-块之后。允许在循环时重新格式化,以使其更易于阅读:
while(true)
{
如果((rv=poll(fds,1100)>0))
{
if(fds[0]。revents和POLLIN)
{
recv(sockfd,buff,200,0);
printf(“来自服务器:%s”,buff);
bzero(buff,sizeof(buff));
}
}
else if(fds[0]。收回和轮询)
{
放置(buff);
strcpy(buff,“你好,世界”);
写入(sockfd、buff、sizeof(buff));
打破
}
}
现在应该很清楚为什么您的POLLOUT
块从未执行过-如果只有在poll()
返回0]时才到达if
语句)
{
if(fds[0]。revents和POLLIN)
{
recv(sockfd,buff,200,0);
printf(“来自服务器:%s”,buff);
bzero(buff,sizeof(buff));
}
else if(fds[0]。收回和轮询)
{
放置(buff);
strcpy(buff,“你好,世界”);
写入(sockfd、buff、sizeof(buff));
打破
}
}
}
当重新格式化为原始编码样式时,将如下所示:
while(true){
如果((rv=poll(fds,1100)>0)){
if(fds[0]。revents和POLLIN){
recv(sockfd,buff,200,0);
printf(“来自服务器:%s”,buff);
bzero(buff,sizeof(buff));
}else if(fds[0]。收回和轮询){
放置(buff);
strcpy(buff,“你好,世界”);
写入(sockfd、buff、sizeof(buff));
打破
}
}
}
看到好的格式有什么不同吗
也就是说,要知道套接字一连接就进入可写状态。因此,您的代码可能会在等待服务器的问候语之前发送客户端的问候语。如果在回复之前需要等待服务器的问候语,则必须首先阅读问候语,例如:
while(true)
{
如果((rv=poll(fds,1100)>0))
{
if(fds[0]。revents和POLLIN)
{
rv=recv(sockfd,buff,200,0);
如果(0))
{
if(fds[0]。revents和POLLIN)
{
rv=recv(sockfd,buff,200,0);
如果(rv 0)
{
rv=发送(fd,pdata,len,0);
如果(rv<0)
打破
pdata+=rv;
len-=rv;
发送+=rv;
}
如果(已发送>0)
{
//从fd的缓冲区中删除发送的字节。。。
}
}
}
}
然后,您可以在需要将任何数据发送到fd
的任何时候使用sendData()
,而不是直接调用write()
/send()
。您忽略了recv
的返回值,这绝不是一个好主意。另外,为什么sizeof(buff)
towrite
?@DavidSchwartz此示例代码已取消了许多检查(例如recv返回值),其范围更多地是一个库,而不是一个独立的程序(因此是sizeof(buff)。您不知道要发送的消息有多大)。任何想法或改进都是好的。如果你不知道要发送的消息有多大,你怎么能发送它?你不需要知道要发送正确的字节数要发送多少字节吗?!非常感谢你的努力。我确实看到了良好的格式使错误更容易被发现。我有一个问题要问你r回答:我怎么知道我什么时候收到了整封邮件?再次感谢您的时间和努力!@kaptsea这就是协议的意义所在。发送方必须以接收方知道何时收到全部邮件的方式格式化其邮件。对于TCP,只有3种方法可以做到这一点:1)在收到之前发送邮件长度e发送消息数据。首先读取长度,然后读取长度所表示的字节数。2)在数据之后发送一个唯一的终止符。继续读取,直到接收到终止符。3)关闭连接。继续读取,直到断开连接。因此,您需要编写代码,以匹配服务器使用的任何协议。让我直说吧;我可以事先决定每条消息将以“\n”结尾或一定的长度,然后读取-recv,直到满足任一标准?这都是我的决定?在这方面没有一些最佳实践吗?哪种是最常见的实现方式?@kaptsea如果您同时编写客户端和服务器,那么是的,这是您的决定,所以请使用适合的方法您的需要。长度前缀适用于可变长度二进制数据,使用终止符适用于文本bas