ZBLOG

把sock设置未非阻塞

将套接字设置为非阻塞模式,可以使用 fcntl 函数。以下是如何在 C++ 中实现这一点的示例,包括对 TCP 和 UDP 的非阻塞套接字设置。

设置非阻塞套接字

#include <iostream>
#include <cstring>
#include <fcntl.h> // for fcntl()
#include <arpa/inet.h>
#include <unistd.h>

int setNonBlocking(int sockfd) {
    int flags = fcntl(sockfd, F_GETFL, 0);
    if (flags == -1) {
        std::cerr << "Failed to get socket flags!" << std::endl;
        return -1;
    }

    if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
        std::cerr << "Failed to set non-blocking!" << std::endl;
        return -1;
    }
    
    return 0; // Success
}

void connectToPeer(const char* ip, int port) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        std::cerr << "Socket creation failed!" << std::endl;
        return;
    }

    // Set the socket to non-blocking mode
    if (setNonBlocking(sockfd) == -1) {
        close(sockfd);
        return;
    }

    struct sockaddr_in peerAddr;
    memset(&peerAddr, 0, sizeof(peerAddr));
    peerAddr.sin_family = AF_INET;
    peerAddr.sin_port = htons(port);
    
   // Convert IP address from text to binary form
   inet_pton(AF_INET, ip, &peerAddr.sin_addr);

   // Initiate connection (this will return immediately in non-blocking mode)
   if (connect(sockfd, (struct sockaddr*)&peerAddr, sizeof(peerAddr)) == -1) {
       if(errno != EINPROGRESS){
           std::cerr << "Connection failed!" << std::endl;
           close(sockfd);
           return; 
       }
   }

   char buffer[1024];
   
   while (true) {
       std::string message;
       std::cout << "Enter message: ";
       getline(std::cin, message);

       send(sockfd, message.c_str(), message.size(), 0); // Send the message

       ssize_t bytesReceived = recv(sockfd, buffer, sizeof(buffer)-1, 0); // Receive a response
       if (bytesReceived > 0) {
           buffer[bytesReceived] = '\0'; // Null-terminate the received data
           std::cout << "Received from peer: " << buffer << std::endl;
       } else if(bytesReceived == -1 && errno != EAGAIN && errno != EWOULDBLOCK){
           perror("recv error");
       }
       
       if (message == "exit") break; // Exit condition
   }
   
   close(sockfd);
}

int main() {
    const char* remoteIp = "192.168.x.x"; // Replace with the other client's IP address
    int remotePort = 5000; // The port you wish to connect to

    connectToPeer(remoteIp, remotePort);

    return 0;
}

UDP 非阻塞示例

对于 UDP 套接字,你可以使用类似的方法来设置它为非阻塞:

void udpClient() {
     int sockfd = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP); 
    
     setNonBlocking(sockfd); // Set as non-blocking
    
     struct sockaddr_in broadcastAddr;

     memset(&broadcastAddr, 0, sizeof(broadcastAddr));

     broadcastAddr.sin_family = AF_INET; 
	// Enable broadcasting on this socket 
	int optval = 1; 
	setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&optval,sizeof(optval));

	broadcastAddr.sin_port = htons(5000); 
	broadcastAddr.sin_addr.s_addr = INADDR_BROADCAST;

	while(true){
		std::string message("Hello from client");
		sendto(sockfd,message.c_str(),message.length(),0,
			(struct sockaddr*)&broadcastAddr,sizeof(broadcastAddr));		
		sleep(1); // Sleep for a second before sending next broadcast.
	}
	
	close(sockfd);
}

void udpServer() {
   int sockfd = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP); 

   setNonBlocking(sockfd); // Set as non-blocking
    
   struct sockaddr_in serverAddr;

   serverAddr.sin_family = AF_INET; 
   serverAddr.sin_addr.s_addr=INADDR_ANY; 
   serverAddr.sin_port=htons(5000); 

   bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)); 

   while(true) {
       char buffer[1024];
       struct sockaddr_in clientAddress; 
       socklen_t clientLength=sizeof(clientAddress);

      ssize_t bytesReceived = recvfrom(sockfd , buffer , sizeof(buffer)-1 , MSG_WAITALL,
               (struct sockaddr*)&clientAddress , &clientLength); 

      if(bytesReceived > 0 ) { 
          buffer[bytesReceived] = '\0'; // Null terminate received string
          std::cout<< "Received: "<<buffer<<" from "<<inet_ntoa(clientAddress.sin_addr)<<std::endl;  
      } else if(bytesReceived == -1 && errno != EAGAIN && errno != EWOULDBLOCK){ 
          perror("recvfrom error");  
      }
   }

close(sockfd);
}

注意事项:

  • 使用非阻塞套接字时,可能会因为没有数据可读而导致 recvrecvfrom 返回 -1,并设置 errnoEAGAINEWOULDBLOCK。这只是意味着当前没有数据可用,而不是错误。
  • 在生产代码中,请确保适当地处理所有返回值和错误情况,以便确保程序稳定性。

如果你有其他问题或需要进一步帮助,请随时询问!


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=6416

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?