0
votes

I would like to make non-block TCP receiver so the cilent can send message to server periodically (i.e. update information every 10 minutes).

I test it in a local machine. 'return_status' value indicates that the 'bind, accept, connect and write' are working correctly but the read always return -1. Can someone explain on this? Thanks

Code of client side.

#define CONTROLPORT 6000

int main(void)
{

int control_sock, return_status;
struct sockaddr_in control_addr;
socklen_t control_len;
memset(&control_addr, 0, sizeof(control_addr));
char control_message[10];

control_sock = socket(AF_INET, SOCK_STREAM, 0);

control_addr.sin_family = AF_INET;
control_addr.sin_addr.s_addr = inet_addr("192.168.16.133");
control_addr.sin_port = htons(CONTROLPORT);

return_status = bind(control_sock, (struct sockaddr *) &control_addr, sizeof(control_addr));

fcntl(control_sock, F_SETFL, O_NONBLOCK); 

return_status = listen(control_sock, 1);
    cout << return_status << endl;
return_status = accept(control_sock, (struct sockaddr *) &control_addr, &control_len); 
    cout << return_status << endl;

while(1){

    return_status = read(control_sock,control_message,sizeof(control_message));

    cout << return_status << endl;

}







}

Code of sender side

#define CONTROLPORT 6000

using namespace std;

int main(void)
{

int control_sock, return_status;
struct sockaddr_in control_addr;
socklen_t control_len;
memset(&control_addr, 0, sizeof(control_addr));
char control_message[10];
control_message[10] = 111;

control_sock = socket(AF_INET, SOCK_STREAM, 0);

control_addr.sin_family = AF_INET;
control_addr.sin_addr.s_addr = inet_addr("192.168.16.133");
control_addr.sin_port = htons(CONTROLPORT);

return_status = connect(control_sock, (struct sockaddr *) &control_addr, sizeof(control_addr));
    cout << return_status << endl;



    return_status = write(control_sock,control_message,sizeof(control_message));

    cout << return_status << endl;

}

3

3 Answers

0
votes

You have set your socket to non-blocking and as such accept is not going to block until some one connects. accept would be returning EAGAIN or EQOULDBLOCK. Check the errno. Without this checks your code proceeds to do the read. And it returns -1 (again check the errno) since the connections has not been established in the first place.

You have to use select, poll or epoll to see for events on non blocking sockets. That is to figure out if someone is connecting /sending data on established connections.

0
votes

If you're going to engage in non-blocking socket programming you have to understand that read() is going to return -1 with errno set to EAGAIN/EWOULDBLOCK when there is nothing to read, and use select() to tell you when it won't.

NB 4 is a valid socket FD in Unix, Solaris, HP-UX, AIDA, Linux, ...

0
votes

In your situation, I don't think non-blocking server is necessary. If you really mean that, you should take a look at select(), epoll and the similar. As to your code, there're several problems:

  1. accept() in the server side should be in the while loop.
  2. accept() returns a descriptor for the accepted socket on success, and this descriptor should pass to read().
  3. As Prabhu's answer says, you have set your socket to O_NONBLOCK, so the accept() would return immediately. If no connections are present to be accepted, the errno would be set to EAGAIN or EWOULDBLOCK.

the code after modification:

int main(void)
{
    int control_sock, return_status;
    struct sockaddr_in control_addr;
    socklen_t control_len;
    memset(&control_addr, 0, sizeof(control_addr));
    char control_message[10];

    control_sock = socket(AF_INET, SOCK_STREAM, 0);

    control_addr.sin_family = AF_INET;
    control_addr.sin_addr.s_addr = inet_addr("192.168.7.134");
    control_addr.sin_port = htons(CONTROLPORT);

    return_status = bind(control_sock, (struct sockaddr *) &control_addr, sizeof(control_addr));

    //fcntl(control_sock, F_SETFL, O_NONBLOCK);

    return_status = listen(control_sock, 1);
    cout << return_status << endl;
    while(1){
        return_status = accept(control_sock, (struct sockaddr *) &control_addr, &control_len);
        cout << return_status << endl;


        return_status = read(return_status,control_message,sizeof(control_message));

        cout << return_status << endl;

    }
}