UNIX Socket FAQ

A forum for questions and answers about network programming on Linux and all other Unix-like systems

You are not logged in.

#1 2004-10-10 10:40 AM

cynthia
Member
Registered: 2004-09-19
Posts: 9

Re: GUI + connect

Hi There,

what's up??? I'm not sure this is the right forum for that but maybe one of you can help.

I built a TCP client server app + GUI. in my client's GUI there's a button 'connect' that starts the connection. after pressing the button the user see 'connecting...' and in case of success 'connected'.

my question is how do you suggest to implement the function that starts working after pressing the button 'connect'. I don't want it to block other buttons in client's GUI as well as other threads in the system.

is there a way to it except for starting another thread that tries to connect() server after pressing the button?

hope you could help me.
THANKX

Offline

#2 2004-10-10 12:13 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: GUI + connect

Offline

#3 2004-10-10 01:01 PM

cynthia
Member
Registered: 2004-09-19
Posts: 9

Re: GUI + connect

I am using non blocking already but the thing is that if server was not 'ON' then the function will not be able to connect(of course).

In this case, I don't want the user that's responsible for the client to press the button 'connect' again and again. I want the code to be responsible for that.

so, I want that one press on the button 'connect' will cause numerous times of trials to reconnect the server before it gives up and announces the user 'client was unable to connect server'.

but I think a loop like:

void WhenConnectButtonIsPressed()
{
       while(1)
      {
             connectServer();
             //Sleep(1000);
      }
}

is not the best way, especially if I use the Sleep() because on this case this thread will be 'frozen' between each trieal and I want other button to be available for the user.

I'll just mention that my Server is on UNIX and the client is multi platform, and that the problem above relates to a client on WINDOWS with MFC interface.

I hope the problem is clear now...
THANKX

Offline

#4 2004-10-10 01:17 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: GUI + connect

I'm not sure if Windows can do non-blocking connect (no idea what MFC is), but if it can then it's just a matter of calling the connect, wait till the socket is writable according to select or whatever you use, then check if it succeeded. If not, check the time to see if you give up, otherwise call connect again and wait for the socket to become writable again. No need for a sleep. You of course need to handle socket writable/readable events asynchrone, but you're making a GUI, which is probably already asynchrone, so that shouldn't be a problem.

To give an idea:

void WhenConnectButtonIsPressed()
{
    if (connectServer() == -1){
        // check for errno here, EALREADY etc.
        if (errno == EINPROGRESS){
            isconnecting = true;
        }    
    } else {
        isconnected  // very unlikely
    }
}

void WhenSocketIsWritable()
{
    if (isconnecting == true){
        // do startup stuff
    } else  {
        // normal write stuff
    }
}


If Windows/MFC doesn't support non-blocking connect then you don't have much choice than a seperate thread just for connecting.

Offline

#5 2004-10-10 02:16 PM

cynthia
Member
Registered: 2004-09-19
Posts: 9

Re: GUI + connect

void WhenConnectButtonIsPressed()
{
    if (connectServer() == -1){
        // check for errno here, EALREADY etc.
        if (errno == EINPROGRESS){
            isconnecting = true;
        }    
    } else {
        isconnected  // very unlikely
    }
}

void WhenSocketIsWritable()
{
    if (isconnecting == true){
        // do startup stuff
    } else  {
        // normal write stuff
    }
}

Offline

#6 2004-10-11 09:00 AM

Nope
Administrator
From: Germany
Registered: 2004-01-24
Posts: 385
Website

Re: GUI + connect

Let's see how much I can post until I have to leave the house...

MFC: Microsoft Foundation Classes. It's meant to speed up development
by providing a "foundation" of classes to handle things. I had a lot trouble
in the past with those, they tend to be slow and were never bug free in my
time. Mind, that was 1995, so there have been some changes to that.


to Q1)
Sockets can operate in 2 main modes of operation. Blocking and non-
blocking. In blocking mode, when you call connect(), the command will not
return as long either the connection is established or the thing timed out
on some level. In non-blocking mode it will always return immediately, no
matter what. You then have to check, for example with select, if the
connection was finished later or an error occured.
The default behaviour for sockets is blocking mode, so you usually have to
set a socket as non-blocking with some commands.

to Q1.1) That's what I usually do:

int flags=fcntl(socket,F_GETFL,0);
fcntl(socket,f_SETFL,O_NONBLOCK|flags);


to Q2)
When you don't use threads but a singe task to handle several
connections, you use non-blocking sockets together with a method to
check if one of those sockets is ready to do its job. Usually with a
command like select. A write on a non-blocking socket will return the
number of bytes written like normal, but if the write would block because
it's not ready (buffers full) it will return -1 and errno will be set to EAGAIN
to mark that this socket would block under normal circumstances. You
then need to wait with for example select until the socket signals that it's
ready again.

to Q3) I think that was what you both meant.
to Q3.1) EINPROGRESS and EALREADY are errno values. There's a define
somewhere to make your code more readable. EINPROGRESS is the value
you get right after the non-blocking connect was called the first time. If
you call connect for the same socket again it will return EALREADY to tell
you that you already try to connect this specific socket and that the
connection is still in progress.


Personally I prefer to use threads to handle IO jobs. It is just easier and
more straight forward to code. This leads normally to a code that's easier
to maintain and develop. As long as gaining the maximum possible speed
is not an issue and as long as the number of threads doesn't go into the
hundreds, it's a viable option.

Offline

#7 2004-10-11 10:28 AM

cynthia
Member
Registered: 2004-09-19
Posts: 9

Re: GUI + connect

thank you so much guys!

nope you helped me understand the terms i386 used, but after explaining it I understand I did know most of the things  :wink:

Still the main problem remains:

how to have the code be responsible to try to connect the server for X seconds after the user press button (MFC).

the socket is non blocked already, but the server tries only once and then stops. if the server was 'ON' it connects, otherwise fails WITHOUT trying to reconnect as I expected it to be.

here is the code I used:

void CComDlg::OnConnect()
{	
	while((timer - timeGetTime()) < MAX_CONNECTING_TIME)		//CHECK
	{
		e_OutputControl.startCom();
	}
}

the function startCom() calls the function connectSocket() that I pasted in a previous reply...
the func

Offline

#8 2004-10-11 01:20 PM

Nope
Administrator
From: Germany
Registered: 2004-01-24
Posts: 385
Website

Re: GUI + connect

I guess you mean the callSocket one.

if (connect(s,(struct sockaddr *)&sa,sizeof sa) < 0)
    {
        close(s);
        return -1;
    }


That's your error. If the socket is indeed non-blocking then connect will
almost always return -1. But -1 is not an error any more, it can also be
the message that the connect is still trying to connect.

if (connect(s,(struct sockaddr *)&sa,sizeof sa) < 0)
    {
        if(errno==EINPROGRESS)
        {
            // no error, the OS still tries to connect in the background
            return -2;
        }
        close(s);
        return -1;
    }


That won't do it either of course, you still have to change your re-
connection routine. Your version is actually really bad, it cycles through
the loop without mercy, eating away CPU time without end.

void CComDlg::OnConnect() 
{    
      e_OutputControl.startCom(); 
      if(e_OutputControl.checkConnect(MAX_CONNECTING_TIME)<0)
      {
         // error
      }
}

int checkConnect(int max_sec)
{
      fd_set check;
      struct timeval to;

      to.tv_sec=max_sec;
      to.tv_usec=0;

      FD_SET(socket,&check);
      int erg=select(socket+1,0,&check,0,&to);
      if(erg==0)
      {
             // timeout of select, check if connect is still trying
            return -2;
      }
      if(erg<0)
      {
            // an error occured within select, might not be related to our socket
            return -1;
      }
      // erg should be 1 if we make it here
      if(getsockopt(socket,SOL_SOCKET,SO_ERROR,&erg,sizeof(int))<0)
      {
            // an error occured during the getsockopt call
            return -1;
      }
      if(erg<0)
      {
            // connect was not successful, check errno here for the reason
            return -1;
      }
      return 0; // socket is connected
}


You see, the first connect only starts the connection process which
continues while you do other things, that's the nature of non-blocking!
In this code snipped I asked select to wait until the socket is either
writable (connected) or time is up. When the time is up without select
returning then the connect is still going on! If select returns writable right
after a connect, it only means that the connect is finished, no statement
about if the connect was successful or not. So I check the sockets error
condition and if that's 0 then all is ok.

I am aware that that's not what you originally asked for as it now blocks in
the select instead the connect. However, if you set the max_sec to 0 the
select will only take a short look if the thing is readable (just polling), so
you can use something like that in your main loop or wherever you want
to to check the status.

Offline

#9 2004-10-11 06:31 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: GUI + connect

Offline

Board footer

Powered by FluxBB