There are a number of ways that you can design a connection-oriented socket server on the iSeries™. These example programs can be used to create your own connection-oriented designs.
While additional socket server designs are possible, the designs provided in these examples are the most common.
In the iterative server example, a single server job handles all incoming connections and all data flows with the client jobs. When the accept() API is completed, the server handles the entire transaction. This is the easiest server to develop, but it does have a few problems. While the server is handling the request from a given client, additional clients can be trying to get to the server. These requests fill the listen() backlog and some of the them are rejected eventually.
In the concurrent server designs, the system uses multiple jobs and threads to handle the incoming connection requests. With a concurrent server there are typically multiple clients that connect to the server at the same time.
For multiple concurrent clients in a network, it is recommended that you use the asynchronous I/O socket APIs. These APIs provide the best performance in networks that have multiple concurrent clients.
The spawn() API is used to create a new job to handle each incoming request. After spawn() is completed, the server can wait on the accept() API for the next incoming connection to be received.
The only problem with this server design is the performance overhead of creating a new job each time a connection is received. You can avoid the performance overhead of the spawn() server example by using prestarted jobs. Instead of creating a new job each time a connection is received, the incoming connection is given to a job that is already active. All of the remaining examples in this topic use prestarted jobs.
The sendmsg() and recvmsg() APIs are used to handle incoming connections. The server prestarts all of the worker jobs when the server job first starts.
For the previous APIs, the worker job does not get involved until after the server receives the incoming connection request. When the multiple accept() APIs are used, each of the worker jobs can be turned into an iterative server. The server job still calls the socket(), bind(), and listen() APIs. When the listen() call is completed, the server creates each of the worker jobs and gives a listening socket to each one of them. All of the worker jobs then call the accept() API. When a client tries to connect to the server, only one accept() call is completed, and that worker handles the connection.