I have unidirectional (both client- and server-) streaming gRPC methods implemented in my golang server. I came across bufconn which enables me to creates my server via in-memory connections in my tests. However, I have logic in my method where I check the peer's address, it always returns "bufconn". I do rely on the peer to provide the IP address along with its port, but I can't really achieve that using bufconn.
What is a canonical (or preferred) way to test gRPC streaming calls in golang?
Is it considered an anti-pattern to rely on peer information in the context?
Related
The gRPC C++ API for creating channels returns a shared_ptr. The generated function NewStub returns a unique_ptr. However I've seen reports of people having issues trying to create multiple instances of a stub type, sharing a channel. Their solution was to share the stub.
It is not clear from the documentation or API if a client is meant to create multiple stub instances sharing the channel or share a single stub. Please clarify the conceptual relationship between stubs, channels, and unique client connections.
Diving a little deeper:
A server can serve more than one service and a client endpoint can use a single channel to connect corresponding stub types to each of those services. For that purpose, it is clear the different stub types share the single channel to talk to the server endpoint. Does gRPC expect only one client per channel for a given service or can I have multiple clients on the client endpoint talking to a single service? If allowed, how do I achieve multiple clients for a given service on a client endpoint? How does the server distinguish these as independent clients?
As an aside, This SO post indicates both Channels and Stubs are thread-safe. (The post is specifically for Java, but I'm assuming it carries over to C++).
I think first we need to clarify the definitions for channel and stub, according to the official documents :
channel :
A gRPC channel provides a connection to a gRPC server on a specified host and port...
Conclude : A channel represents a single TCP connection.
stub :
On the client side, the client has a local object known as stub (for some languages, the preferred term is client) that implements the same methods as the service.
Conclude : A stub represents a single client.
From reading many other materials, I'm sure that a single channel(tcp connection) can be multiplexed, and now we get two options to achieve it:
one channel <--> one stub
one stub <--> multiple streams
one channel <--> multiple stubs
one stub <--> multiple streams
the only difference is that whether to share a channel among the stubs or not. My answer is: Yes, you can, for the reasons:
your reports of people having issues example is written in ruby, but I can also find python examples standing on the opposite side. So the behavior may depends on language implementations.
the synchronous cpp client examples use one stub object to issue a rpc, and it doesn't have any stream objects associated with, then the only way for multiplexing purpose is just share one single channel object among the stubs.
Combining the above two reasons, I conclude that: sharing a channel among the stubs is valid in C++.
Now, back to you questions:
Does gRPC expect only one client per channel for a given service or can I have multiple clients on the client endpoint talking to a single service?
Sure, you can have multiple clients talking to a single service.
If allowed, how do I achieve multiple clients for a given service on a client endpoint?
You can just have multiple stubs generated either from one single channel or from multiple channels, former is a better choice for connection overhead considerations.
How does the server distinguish these as independent clients?
This is due to http2, it can be multiplexed and has its own rules to achieve this, what grpc need to do is just follow thoes rules.
Hope this helps!
I'm currently considering to use gRPC for basically inter-process communication between Java app (client) and C++ server. The RPC calls will use functionality from very old C++ code base which is definitely not thread-safe.
Normally the Java client will start more gRPC server instances and have just one connection with each server instance.
Is there any way how to ensure this on the gRPC server to accept just one connection and refuse all other attempts for connection. Otherwise I need to introduce some global lock in the RPC functions to have 100% correct server implementation.
There are plans to provide additional server side APIs that will allow the server to decide whether or not to accept an incoming connection, but this is not done yet. For now, a lock is probably a reasonable option.
We have internal services in our application, which are basically developed as Thrift RPC services. Now, I need to expose these services to the client applications, which are outside of the core system.
Now, the question is:
should I expose these Thrift services directly to the client? Advantages of doing so would be least amount of work required. Disadvantage would be that the clients need to connect to these Thrift APIs as well as another interface, which already exists, so actually the client applications need to open more than one socket to make connection to the core system.
An alternate option would be to wrap these Thrift services in another layer, which will be ultimately delivered to the end clients. Disadvantage of doing this: doing marshalling/unmarshalling the data twice, once with Thrift and next time with another interface.
What should be the preferred way of handling this situation?
We would not expose these services directly to outside clients. We would build or use an application to configure a proxy that the external clients could connect to.
The advantages to this are:
No need to punch a hole in your firewall
Possibility to do an extra security check
Possibility to throttle access to the internal service
Less chance of a hacker being able to exploit service
As the headline says, how would you test a client/server application, that is written in C/C++, that talks through a protocol over a network? Im a bit confused on how to do this. I have thought about making some mocking, but I have never tried mocking, so I dont know if this is the best way.
How should I do this? I have written many unit tests, but never tried to test something that interact over a network.
I use the command pattern in the unit test driver (client) to send test commands to the server. The advantage of this is that the test is coded in one place.
Example for testing a request timeout:
Client sends a sleep command to server and then the request. The request times out and the test case is passed.
Typically you'll want to use mocking to verify that each side reacts as required to messages from the other side (e.g., that when the client receives a response from the server that it processes that response correctly).
To test the network functionality itself, you can test both running on the same machine, and you can run one (or both) inside a virtual machine. If you have two network adapters, you can even dedicate each to a virtual machine so the network traffic actually goes out one, to a switch/router, and comes back in the other (particularly useful when/if you want to capture and verify packets).
I have some client/server code that I unit test through the loopback address. I use some mocks when I have to test error conditions. So, I test with the real code when I can and the mocks when I need to trigger very specific conditions.
In a normal client/server design, the client can execute functions implemented on the server-side. Is it possible to test a gSOAP server by connecting an extra client to it?
I have not used gSOAP, but from reading the documentation it allows you to write both clients and servers so you can write an test client to test the service.
However if you are planning to offer the service to clients written in .net or java I would recommend that you write the test client in one of these. This way you will know for certain that it is possible to use the service from one of these clients. You might also find that .net or java clients are easier to write if you server is designed in a specific way, your test client will help you find this out.
Sure it is, use SoapUI to generate client connections and data. Its free.
To add to the other comments: testing a gSOAP server can be easily done offline using IO redirect. When you invoke soap_serve() without any sockets set up prior to this call, the server engine will simply accept data from standard input and write data to standard output. This is a great way to hit an offline server implementation hard with XML data patterns for testing before deploying the server online. The gSOAP tool even generates example XML messages that you can use for this purpose.