Sockets 带有BSD套接字的错误文件描述符

Sockets 带有BSD套接字的错误文件描述符,sockets,send,bsd,file-descriptor,errno,Sockets,Send,Bsd,File Descriptor,Errno,当我尝试将数据从tcp服务器发送到tcp客户端时,我不断收到“错误的文件描述符”错误。就插座而言,这意味着什么?我已经做了一段时间了,我不知道我的代码有什么问题。这与我两天前使用的代码基本相同,而且代码运行良好。我希望有人能告诉我,当试图通过套接字发送时,坏文件描述符的常见原因是什么,以及我如何检查/修复它们。感谢您的帮助。我将在下面发布一些代码,以防有所帮助 /*Waits to connect a client. Returns true if successful*/ bool TcpSe

当我尝试将数据从tcp服务器发送到tcp客户端时,我不断收到“错误的文件描述符”错误。就插座而言,这意味着什么?我已经做了一段时间了,我不知道我的代码有什么问题。这与我两天前使用的代码基本相同,而且代码运行良好。我希望有人能告诉我,当试图通过套接字发送时,坏文件描述符的常见原因是什么,以及我如何检查/修复它们。感谢您的帮助。我将在下面发布一些代码,以防有所帮助

/*Waits to connect a client. Returns true if successful*/
bool TcpServer::launchServer() {
int status;

struct addrinfo hints;
struct addrinfo *servinfo;  //will point to the results

//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;


memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;  //ipv4
hints.ai_socktype = SOCK_STREAM; //tcp

//get server info, put into servinfo
if ((status = getaddrinfo("192.168.2.3", port, &hints, &servinfo)) != 0) {
    printf("\ngetaddrinfo error: %m", errno);
    return false;
}

//make socket
fd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (fd < 0) {
    printf("\nserver socket failure %m", errno);
    return false;
}

//allow reuse of port
int yes=1;
if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*) &yes,sizeof(int)) == -1) {
    perror("setsockopt");
    return false;
}

//bind
if(bind (fd, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
    printf("\nBind error %m", errno);
    return false;
}

//free up space
freeaddrinfo(servinfo);

//listen
if(listen(fd, 5) < 0) {
    printf("\nListen error %m", errno);
    return false;
}
their_addr_size = sizeof(their_addr);


//accept
comm_fd = accept(fd, (struct sockaddr*)&their_addr, &their_addr_size);
if( comm_fd < 0) {
    printf("\nAccept error %m", errno);
    return false;
}

return true;
}   //END LAUNCHSERVER






void TcpServer::communicate() {


fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd = {10, 0};          // the max wait time for an event
int sel;        // holds return value for select();
int numRead;    //holds return value for read()
int numSent;    //holds return value for send()
char in[255];   //in buffer
char out[255];  //out buffer

//clear buffersz
memset(&in, 0, 255);
memset(&out, 0, 255);


while(!done) {
    FD_ZERO(&read_flags);
    FD_ZERO(&write_flags);
    FD_SET(comm_fd, &read_flags);
    FD_SET(comm_fd, &write_flags);
    FD_SET(STDIN_FILENO, &read_flags);
    FD_SET(STDIN_FILENO, &write_flags);

    //call select
    sel = select(comm_fd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);

    //if an error with select
    if(sel < 0)
        continue;

    //if socket ready for reading
    if(FD_ISSET(comm_fd, &read_flags)) {

        //clear set
        FD_CLR(comm_fd, &read_flags);

        memset(&in, 0, 255);

        numRead = recv(comm_fd, in, 255, 0);
        //if an error, exit
        if(numRead < 0) {
            printf("\nError reading %m", errno);
            myAgent->getRobot()->pauseSensorStream();
            done = true;
        }   //end if error
        //if connection closed, exit
        else if(numRead == 0) {
            printf("\nClosing socket");
            close(comm_fd);
            done = true;
        }   //end if connection closed
        //if message, call getsendback
        else if(in[0] != '\0') {
            //std::cout<<"\nClient: "<<in;
            getSendBack(in);
        }   //end if message
    }   //end if ready for read


    //if stdin is ready for reading
    if(FD_ISSET(STDIN_FILENO, &read_flags))
        fgets(out, 255, stdin);


    //if socket ready for writing
    if(FD_ISSET(comm_fd, &write_flags)) {

        //printf("\nSocket ready for write");
        FD_CLR(comm_fd, &write_flags);

        //check validity by checking for a digit
        if(isdigit(out[0])) {

            //create message to send
            std::stringstream tosend;
            tosend<<"@ "<<out;
            //std::cout<<"\ntosend: "<<tosend.str();

            //send
            //********ERROR HAPPENS HERE PRINTS OUT MESSAGE BELOW******
            numSent = send(comm_fd, tosend.str().c_str(), tosend.str().length(), 0);
        }   //end if valid message
        //if error, exit
        if(numSent < 0) {
            printf("\nError sending %m", errno);
            done = true;
        }   //end if error
        //wait for message to get there, then clear
        usleep(5000);
        memset(&out, 0, 255);
    }   //end if
}   //end while
}   //END COMMUNICATE
/*等待连接客户端。如果成功,则返回true*/
booltcpserver::launchServer(){
智力状态;
结构addrinfo提示;
struct addrinfo*servinfo;//将指向结果
//存储连接地址和大小
结构sockaddr\u存储它们的地址;
袜子的地址和尺寸;
memset(&hints,0,sizeof hints);//确保结构为空
hits.ai_family=AF_INET;//ipv4
hints.ai_socktype=SOCK_STREAM;//tcp
//获取服务器信息,放入服务信息
if((status=getaddrinfo(“192.168.2.3”,端口、提示和服务信息))!=0){
printf(“\nGetAddressInfo错误:%m”,错误号);
返回false;
}
//制作插座
fd=套接字(servinfo->ai_系列,servinfo->ai_socktype,servinfo->ai_协议);
如果(fd<0){
printf(“\n服务器套接字故障%m”,错误号);
返回false;
}
//允许重用端口
int yes=1;
if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&是,sizeof(int))=-1){
perror(“setsockopt”);
返回false;
}
//束缚
如果(绑定(fd,servinfo->ai_地址,servinfo->ai_地址)<0){
printf(“\n绑定错误%m”,错误号);
返回false;
}
//腾出空间
freeaddrinfo(servinfo);
//听
如果(听(fd,5)<0){
printf(“\n列表错误%m”,错误号);
返回false;
}
他们的地址大小=sizeof(他们的地址);
//接受
comm_fd=accept(fd,(struct sockaddr*)及其地址和大小);
如果(通信fd<0){
printf(“\n接受错误%m”,错误号);
返回false;
}
返回true;
}//结束启动服务器
void TcpServer::communicate(){
fd_set read_flags,write_flags;//要使用的标志集
struct timeval waitd={10,0};//事件的最大等待时间
int sel;//保存select()的返回值;
int numRead;//保存read()的返回值
int numSent;//保存send()的返回值
[255];//缓冲区中的字符
字符输出[255];//输出缓冲区
//清除缓冲区
memset(&in,0255);
内存集(&out,0,255);
而(!完成){
FD_零(&读取_标志);
FD_零(&write_标志);
FD_设置(comm_FD和read_标志);
FD_集(comm_FD和write_标志);
FD_集(标准文件号和读取标志);
FD_集(标准文件号和写入标志);
//呼叫选择
sel=select(comm_fd+1、读取标志和写入标志、(fd_set*)0和waitd);
//如果select出现错误
如果(sel<0)
继续;
//如果插座准备好读取
if(FD_ISSET(comm_FD和read_标志)){
//清晰设置
FD_CLR(comm_FD和read_标志);
memset(&in,0255);
numRead=recv(comm_fd,in,255,0);
//如果出现错误,请退出
if(numRead<0){
printf(“\n读取%m时出错”,错误号);
myAgent->getRobot()->pauseSensorStream();
完成=正确;
}//如果出现错误,则结束
//如果连接关闭,请退出
else if(numRead==0){
printf(“\n闭合插座”);
关闭(通信fd);
完成=正确;
}//如果连接关闭,则结束
//如果出现此消息,请调用getsendback
else if(在[0]!='\0'中){
//当errno为EBADF时,程序将打印“坏文件描述符”。
从发送的手册页:

EBADF=指定的描述符无效

我很确定在send()调用之前套接字已关闭。 这是可能发生的,因为在“连接关闭”分支之后,程序可以转到“准备写入”分支

请尝试以下操作:

else if(numRead == 0) {
    printf("\nClosing socket");
    close(comm_fd);
    break;
} 
而不是:

    else if(numRead == 0) {
        printf("\nClosing socket");
        close(comm_fd);
        done = true;
    }

您回答了自己的问题。如果没有显式初始化numSent和numRead,您将得到垃圾,这可能恰好是numSent的负数,如果out[]中没有数字,这将导致它出错数组。

您能在发送之前打印
fd
吗?我打印了,comm\u fd值为4。您的代码是否在错误消息之前打印“Closing socket”?错误意味着文件描述符已经关闭。一旦关闭,就不能再使用文件描述符。是的,但您的代码需要“break”。我更新了我的答案,因此更容易看到建议的更改。这没有改变任何东西。为什么会这样?更清楚地说,错误发生在我的程序开始时。我每0.2秒发送一次消息,在它发送第一条消息后,它会给我错误。正如您所看到的,代码可以在close()之后调用send()。如果它没有解决问题,那么还有另一个问题。我不确定这是否有效,但如果我将numSent和numRead初始化为0,我就不会再收到错误。我猜这只是在初始化为任何内容之前到达If语句?