Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!wuarchive!psuvax1!rutgers!aramis.rutgers.edu!athos.rutgers.edu!hedrick From: hedrick@athos.rutgers.edu (Charles Hedrick) Newsgroups: comp.protocols.tcp-ip Subject: Sockets vs streams. An attempt to answer the original question Message-ID: Date: 27 Aug 90 21:09:48 GMT References: <9008242107.AA19843@ucbvax.Berkeley.EDU> <1990Aug27.111656.1@amazon.llnl.gov> Organization: Rutgers Univ., New Brunswick, N.J. Lines: 78 Before we got diverted, the original question was whether code that needs to access the network should use sockets or streams. Since then, I've looked up the streams documentation in SunOS 4.1. I'm going to assume that's typical of what streams is like, but of course that could be wrong. So take this with a grain of salt. In my opinion, if you want to support a full range of systems, you're going to have to deal with both sockets and streams. So that's not the basic design choice. It's also not a big issue anyway. All network code that I've seen has subroutines for doing the low-level network operations such as openning connections. These are not complex subroutines. Maybe half a page each. They just do the right combination of socket, bind, connect, etc. So the streams version is going to have another version of the subroutine to open a connection, that uses t_bind and t_connect instead of bind and connect. Big deal. Similarly, data transfer subroutines can use send and recv for Berkeley and t_snd and t_rcv for the streams version. The real issue seems to be not this, but the problem that streams doesn't fit the normal Unix view of I/O. At least in SunOS 4.1, you can't do read and write on a stream. Thus the special t_snd and t_rcv calls for I/O. Sockets allow you to use either special send and recv calls, which allow more detailed control over network-level handling, or normal read and write. But SunOS provides a streams module you can push that gives you read and write. It can't deal with out of band data, but if you know your application doesn't use OOB, it might be usable. It seems clear that you can get streams/sockets compatibility by doing everything with subroutines and supplying streams and sockets versions for everything. But there are two questions that can really only be answered by people who have experience with using streams: (1) What is the performance penalty for using the read/write interface in streams? With sockets, the send/recv interface is at the same level as the read/write interface, so there's no reason to expect any performance penalty for using read and write. Indeed it's very rare that you see programs using send and recv. This allows you to use things like printf, and to set primary input or output to a socket. With a stream, if you want to do this, you have to push on the read/write interface. I could imagine ways of implementing it that wouldn't result in any more overhead than doing the low-level I/O, but there's no way to know whether this will happen in real implementations other than trying it. If read/write turns out to be unacceptable under streams, then you'll need to go to the approach of using subroutines or macros for your low-level code, so that you can supply both socket and streams versions. (By the way, the original ATT claim was that sockets were a terrible wart on Unix, and streams were "clean". I'm not sure what -- if anything -- that meant. It seems to me that sockets makes network I/O look a lot more like normal file I/O than streams do.) (2) Is it a good idea to use the "sockets library"? Comments have been made about both overhead and portability. Again, this is an issue that only experience can settle. Most applications of sockets that I've seen use read and write. In this case, all you need the sockets library for is to open and close the connection. Once it's open, you're going to use read and write directly, which will not need to pass through any sockets emulation. So this seems to reduce to the previous question, of whether the read/write interface to streams has too much overhead. Whether it makes sense to use the sockets library for opening and closing seems to reduce to the issue of how good the sockets libraries are and how compatible the streams implementations are. Clearly streams itself is just a framework. It's only the actual device drivers and streams modules that determine whether two implementations look at all alike. One could imagine a world in which each streams implementation looks different, but all their socket emulation libraries are fairly compatible. One could also imagine a world in which everyone used the same streams code, but the socket libraries are very flaky. In the first case, you'd be better off to use sockets, in the second you'd be better off to use streams. Since it's hard to get reliable information on any of these topics, I think I'd make sure that my code is designed in such a way that you can handle either case. That is, I'd run all network operations -- opening, closing, and actual I/O -- through low-level subroutines or macros that are designed so you can implement them with either sockets or streams.