Subject: CSI TCP/IP Socket Send Techniques
From: Don Stoever (don@e-vse.com)
Date: Tue Aug 19 2008 - 10:38:44 EDT
Hello vse-L friends, I have returned from a sabbatical (rode Harley Road King from Columbus,OH. to Sturgis,SD and back), and after reviewing some of the postings from the: "RE: SOCKET RECEIVE techniques..." thread I have decided to start a new thread and change the title from: "RE: SOCKET RECEIVE techniques..." to: "CSI TCP/IP Socket Send Techniques", and add some actual send techniques for sending data. The assembler SOCKET macro is the lowest level api that we provide, and allows the assembler based applications the flexibility to send data with or without waiting for sent data to be acknowledged by the foreign stack. The SEND operation can transmit chunks of data of almost any size. The data will be queued and carved-up into proper sized chunks to send over the network. There are several techiques for maximizing throughput. The first is for the application to reasonably buffer its data. Issuing lots of small SENDs because "it's easier" is not the mark of a good programmer. In addition to increasing the amount of time required to transfer data, such technique adds unnecessary overhead, and consumes more CPU cycles. For those wishing to code highly-efficient, fast transports, it is necessary to include use of the "FAST" option of the SOCKET macro. Simply, coding "FAST" tells the stack to queue the operation but NOT to inform the application when it completes. This puts some additional demands on the application, both in the detection and recovery of errors, as well as not to "flood" the stack with data. These recommenedations would be for a appliction that is primarily sending out a large amount of data in multiple send requests without a application receive before each send request. For applications that issue a send followed by a receive I would recommend using the simple send then wait for the ecb to be posted (at least you then know in your application that the data has been received by the foreign stack). Your application can then issue it's receive. But when sending large amounts of data from VSE consider one of the following techniques for customer or vendor applications: 1) Use the socket macro with 2 send buffers with separate result areas(SRBLOK's). The first fullword of the SRBLOK contains the ecb that can optionally be waited on to verify the sent data has been ack'ed by the corresponding foreign stack. Let's call them sendbufA and sendbufB. Fill sendbufA and send it out without waiting, and continue to fill sendbufB. When sendbufB is full and ready to send immediately send it, and then wait on sendbufA's ecb. Using this simple method of buffer overlapping should keep enough data queued to the foreign stack, and minimize delays without having to worry about tcp window closing or excessive storage usage. You could also design and modify this technique for using 3 or 4 overlapping send buffers. 2) Use the socket macro with fast=yes to send out data. You must check R15 after issuing this call and if it is zero then all the data will have been copied to the TCP/IP partition. The SRBLOK and data buffer can then immediately be reused for the next send request with fast=yes. The data will be parsed and sent out in datagrams(ibbk's) by the TCP/IP partition. When the application terminates it should issue a close with fast=no, and wait for the close to complete. The close will generate a final datagram with a FIN setting, so if the close successfully completes your application will then at least know that all the sent data has made it through the network and been acknowledged by the foreign stack. Which, I would think is a good thing. Would you really want to send out data and have the job step terminate with a zero return code, and the data has not even arrived/been acknowledged by the foreign connection? Your application could also issue the close with fast=yes, and the fin will be sent, with no wait in your application. I would not recommend doing this though since it leaves a large question about the other stack actually successfully receiving the sent data. I would only recommend this if the foreign application is designed to send some sort of final I got your sent data, and the application on VSE ends with a final receive for this final application level acknowledgment that the data was received. The FTP protocol with it's final "226 TRANSFER FINISHED SUCCESSFULLY" is an example of a application that sends out a final message when all of the data has been successfully transferred. 3) This is really a slight modification of option 2 above. This is more or less the technique used in our BSD/C socket interface. Issue a socket status call before issuing each send(or on every other send request). The returned connection status block(STBLOK) contains 2 double word fields: STSQSEQ Next seq to be sent STSUNACK Next unacked seq no. STSQSEQ - STSUNACK = the number of bytes sent but not acknowledged by the foreign stack. You could set a arbitrary value of 512k or more and slow down your application send by issuing a send with a wait to allow the network to digest/get caught up with the un'acked data. Or issue a timer then reissue the status and resume send with fast=yes when the unack'ed count gets below 256k(or any other selected value). Then once the un'acked count is acceptable continue the sends with fast=yes. 4) Use the BSD/C API and $SOCKOPT.phase sockopt settings to control sending of data. The name(BSD/C) seems to indicate that this api can only be called from C applications, but it can be called from any language that has standard call/save linkage, including Assembler, Cobol, PL/1, etc. More accurately it could be called the Basic Socket API. Historically it is the defacto standard for coding TCP/IP applications. It's concepts for server's using bind, listen and accept for establishing new connections, and clients using connect is widely published, but not in any official RFC for IPv4 that I am aware of. The IPv6 RFC3493 titled "Basic Socket Interface Extensions for IPv6" contains the following introduction: The de facto standard Application Program Interface (API) for TCP/IP applications is the "sockets" interface. Although this API was developed for Unix in the early 1980s it has also been implemented on a wide variety of non-Unix systems. TCP/IP applications written using the sockets API have in the past enjoyed a high degree of portability... This RFC does contain a good and official definition for the BSD API functions, but is directed to IPv6. Well, I think that is enough to chew on for now. Hope it helps. Don Stoever CSI TCP/IP Product Developer
This archive was generated by hypermail 2b25 : Tue Aug 19 2008 - 17:50:13 EDT