How build a service (one port) with ServerBuilder from a range of ports, using the next free? (C++)

1,194 views
Skip to first unread message

tobias.f...@zuken.com

unread,
Nov 13, 2017, 10:23:23 AM11/13/17
to grpc.io

I will use the ServerBuilder to create an service with one of a port of my defined port range ( e.g. 50001 to 50100 )
If one port is used I will use the next one.

Is this possible and how is this working? I will not check for free port before.

I tried the following:
  • instantiate the builder
  • add completion queue
  • add one of the port to builder -> AddListeningPort(L"0.0.0.0:50001", grpc::InsecureServerCredentials()
  • instantiate new service
  • register service
  • and call BuildAndStart()
  • if nullptr returned I try it again with an other port.
-> this is not working. An exception occured ( Unhandled exception at 0x0f365dc4 (xxxx.dll) in xxxx.exe: 0xC0000005: Access violation reading location 0xfeeefef2. )
in method has_synchronous_methods() at for loop
  bool has_synchronous_methods() const {
    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
     
if (*it && (*it)->handler() != nullptr) {
       
return true;
     
}
   
}
   
return false;
 
}




Here is my code (simplyfied):

void MyService::Run( )
{
   
ServerBuilder builder;
    _completionQueue
= builder.AddCompletionQueue();
   
   
for( int portNumber = 50000; portNumber <= 50100; portNumber++ )
   
{
        _runningService = std::make_shared<MyServiceBase>();
        builder
.AddListeningPort( _address + ":" + std::to_string( portNumber ), grpc::InsecureServerCredentials(), &_port);
        builder
.RegisterService( _runningService.get() );

        _server
= builder.BuildAndStart();

       
if( !_server )
           
return;
   
}

   
HandleRpcs();
}


Thanks in advanced.

Kind regards

Sree Kuchibhotla

unread,
Dec 5, 2017, 7:06:50 PM12/5/17
to grpc.io
Sorry for the late response.

The BuildAndStart() does not promise you that it would return a "nullptr" if the port you passed is already in use.

You need to use alternative ways to find an unused port yourself.  
You could do the check yourself by randomly selecting a port number, creating a test socket and attempting to bind to that port. If successful, close the test-socket and use that port number for your gprc server.

For example, in grpc unit tests (where we have to create many servers), we wrote a simple port-server utility (https://github.com/grpc/grpc/blob/master/tools/run_tests/python_utils/port_server.py) that maintains a list of available ports (it find the available ports by using pretty much the same logic I described above)

Hope this helps,
-Sree

tfzk

unread,
Dec 6, 2017, 10:09:25 AM12/6/17
to grpc.io

Thanks for the answer.

I understand that the BuildAndStart() method is not save for that doing.

But my problem is an other thing.
What is if the port get used from an other process in between the port check and the BuildAndStart() call? -> The ServerBuilder comes in a strange state.

-> I can not use the ServerBuilder in my process again. I can not reset the ServerBuilder.
    If I call the BuildAndStart(...) again an exception occured. That is my problem.

-> An exception occured ( Unhandled exception at 0x0f365dc4 (xxxx.dll) in xxxx.exe: 0xC0000005: Access violation reading location 0xfeeefef2. )

    in method has_synchronous_methods() at for loop

-> And the ServerBuilder could only instantiate once.

Is there any solutions for this problem or is this a bug or missing functionality in the ServerBuilder class?

Kind regards

Sree Kuchibhotla

unread,
Jan 9, 2018, 2:16:22 PM1/9/18
to grpc.io
I apologize for the late response again. You probably already figured this out by now but 

You could also do builder -> AddListeningPort("address:0", creds, &selected_port)  
(i.e pass port number as "0" when you pass the address to AddListeningPort API) and this picks an available port and returns via selected_port

(The only issue with this is that you will then have to figure out a way to let your client know what the server port is. This is why, we use a 'port server' utility in our unit tests that I mentioned earlier..Yes, It does have the issue you mentioned in theory- i.e the port might be used by some other process between the port check and BuildAndStart)

-Sree
Reply all
Reply to author
Forward
0 new messages