使用选择而不听()ing,可能
Using select without listen()ing, possible?
我正在构建一个客户端:
- 应该能够从服务器和标准输入接收信息
- 应该能够在不询问的情况下从服务器接收信息,例如当另一个客户端发送消息时。
为此,我尝试使用 select 来监视两个可能的输入。
发生的情况是,当键盘输入被监控时,我向客户端发送一条消息,我希望返回一条消息,所以没有问题。但是当服务器发送意外消息时,没有任何反应,我不知道为什么。使用 select() 是正确的方法吗?甚至可以在不listen()
的情况下使用select()
吗?
这是我的代码(可编译):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#define MAX_CLIENT_NAME 30
#define MAX_TWIT_SIZE 140
#define NUM_OF_ARG 4
#define ERROR -1
#define GREAT_SUCCESS 0
#define OK "OK"
#define EXIT "EXIT"
using std::string;
using std::cerr;
using std::endl;
using std::cout;
string clientName;
int srverfd, numbytes, status, maxSock ;
fd_set inputFdSet; /* Socket file descriptors we want to wake
up for, using select() */
int establishConnection(char * serverAddress,char * port){
if ((srverfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return ERROR;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
inet_aton(serverAddress, &server.sin_addr);
server.sin_port = htons(atoi(port));
memset(&(server.sin_zero), ' ', 8);
if (connect(srverfd,(const struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("connect");
close(srverfd);
return ERROR;
}
maxSock = srverfd;
return GREAT_SUCCESS;
}
const char * getUserTweet(){
string temp;
getline(std::cin,temp);
return temp.c_str();
}
void sendMessage(string message){
if ((numbytes = send(srverfd, message.c_str(), message.length(), 0)) == -1) {
perror("sendMessage");
close(srverfd);
}
cout<<"Message sent: "<< message << endl;
return;
}
const char * getMessage(){
char buf[MAX_TWIT_SIZE];
memset(buf,' ',MAX_TWIT_SIZE);
if ((numbytes = recv(srverfd, buf, 140, 0)) == -1) {
perror("getMessage");
close(srverfd);
}
string temp = buf;
return temp.c_str();
}
void build_select_list() {
FD_ZERO(&inputFdSet);
FD_SET(srverfd,&inputFdSet);
FD_SET(STDIN_FILENO,&inputFdSet);
if (STDIN_FILENO > maxSock)
maxSock = STDIN_FILENO;
return;
}
void readSocket(fd_set tempfd) {
const char * tweet, * inMessage;
if (FD_ISSET(srverfd,&tempfd)) {
inMessage = getMessage();
cout << inMessage << endl;
}
if (FD_ISSET(STDIN_FILENO,&tempfd)) {
tweet = getUserTweet();
sendMessage(tweet);
inMessage = getMessage();
if (strcmp(inMessage,OK) != 0) {
cout << inMessage << endl;
}
if (strcmp(inMessage,EXIT) == 0) {
return;
}
}
return;
}
int main (int argc, char *argv[] ){
int value;
bool clientON = false;
if(establishConnection(argv[2],argv[3])){
cerr << "usage: failed to make connection" << endl << "exiting..." << endl;
exit(EXIT_FAILURE);
}
cout << "Connected successfully" << endl;
sendMessage("CONNECT "+clientName); //Connect
if(strcmp(getMessage(),OK) == 0){
clientON = true;
}
while(clientON){
build_select_list();
value = select(maxSock, &inputFdSet, NULL, NULL, NULL);
if (value < 0) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
continue;
}
else {
readSocket(inputFdSet);
}
}
sendMessage("DISCONNECT");
if(strcmp(getMessage(),OK) == 0){
// do nothing
}
close(srverfd);
return 0;
}
您的select
调用无效。第一个参数必须是任何集中的最高文件描述符加 1。
正如你所看到的,srverfd
上的事件不会"唤醒"select
调用(除非STDIN_FILENO
以某种方式小于srverfd
,在这种情况下,stdin
事件不会解锁select
- 但这在实践中不会发生)。
您的代码还有很多其他问题。(它看起来不像C++。
getUserTweet
是不可靠的(未定义的行为 - 一旦函数返回temp
就会被销毁,因此当调用者尝试使用它时,您返回char*
已经消失了)。getMessage
也一样。要解决此问题,请在任何地方使用 std::string
,并且仅在调用 C 库函数时提取char*
)。
readSocket
不必要地复制 FD 集(可能很昂贵)。
你真的应该摆脱所有这些全局变量 - 构建一个或两个类来封装该状态和网络函数,或类似的东西。
相关文章:
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 有可能在Armadillo中复制MATLAB circshift方法吗
- GCC对可能有效的代码抛出init list生存期警告
- malloc() 可能出现内存泄漏
- C++quit()函数中可能存在作用域问题
- 变量可能尚未初始化[MIRA 2012规则9.1,强制性]
- 有没有可能有一个只有ADL才能找到的非好友功能
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在他自己的方法中,有可能将一个对象取消引用到另一个对象吗
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- 有可能使shared_ptr协变吗
- 尝试将lambda函数放在队列中时出现一般分配器错误(可能是与unique_ptr有关的错误)
- 有可能在信号处理程序中设置promise吗
- 检查向量是否具有所有可能的字符组合
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- 读取文件中所有可能的十六进制 16 字节序列并打印每个序列
- std::背后的基本原理assignable_from可能的实现
- 对于循环C++可能效率低下
- 使用选择而不听()ing,可能