Movatterモバイル変換


[0]ホーム

URL:


Winsock Programmer’s FAQ
Articles: BSD Sockets Compatibility

BSD Sockets Compatibility

by Warren Young

So you say you’re a long-time Unix hacker who’s new toWindows programming? And you’ve heard of this great API calledWinsock that’s compatible with your beloved BSD sockets, but tryas you might, you just can’t find thereadv() call? Wellbunky, this is the article for you.

Introduction

In the beginning, there was chaos in the world of Windows TCP/IPAPIs. A program written for, say, FTP Software’s TCP/IP stackwouldn’t run on JSB’s stack.

Then, sometime in 1990, a bunch of people got together and decidedto make one nice, big, compatible API called Windows Sockets thatwould allow a single program to run on any vendor’s stack. Theydecided to base this API on the popular BSD sockets model of networkprogramming, but for various reasons, there are still many differencesbetween Winsock and BSD sockets. This article points out how Winsockdiffers from BSD sockets, and how to translate BSD sockets programsto use similar Winsock functionality.

The Official Word

The Winsock API documentation has a section calledPortingSocket Applications to Winsock that covers many of the same issuesthat this article does, and a few others besides.

#include Differences

Under BSD sockets, there are quite a few different header files youneed to include, depending on what sockets calls you use. A typical BSDsockets program has a block of #includes near the top like this:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

For Winsock, you don’t need any of these. Instead, youjust need to include winsock.h. (Or, if you need Winsock 2-specificfunctionality, winsock2.h.)

errno vs.WSAGetLastError()

WSAGetLastError() is essentially the same thing asUnix’serrno global variable. The error constants andtheir values are different; there’s a table in the Winsockspec where it lists all the error constants, one column of whichshows the equivalent BSD error constant for a given Winsock errorconstant. Usually the difference is just the addition of "WSA" to thebeginning of the constant name for the Winsock versions. (E.g. WSAEINTRis the Winsock version of BSD’s EINTR error constant.)

Another thing to keep in mind is that, although theperror()call exists in most Windows compilers' run-time libraries, itdoesn’t work for Winsock calls. (This is a consequenceof Winsock not returning its error codes in theerrnovariable.) There is a function calledWSAGetLastErrorMessage()in thebasic Winsock examples area ofthe FAQ that you can use to build aperror()-like function.It’s in the ws-util.cpp module.

EAGAIN

Many Unix programs, especially those with System V roots, checkfor the EAGAIN value in the globalerrno variable whena non-blocking call fails. This is the same thing as BSD’sEWOULDBLOCK and Winsock’s WSAEWOULDBLOCK errors. You’llhave to check your system’s header files, but all UnixesI’ve checked on this matter #define EAGAIN and EWOULDBLOCKto the same value, so you may want to get into the habit of usingEWOULDBLOCK instead of EAGAIN under Unix, to make transitions to andfrom Winsock easier.

Equivalence of File and Socket Handles

Under Unix, the I/O system calls work with file descriptors andsocket descriptors equally well. For example, the only reason to callrecv() on a socket instead ofread() is when you need to setone of the flags allowed in the fourth parameter torecv().

The situation is the same under allmodern versions of Windows, exceptthat the functions are named differently:ReadFile() instead ofread(), for example.

That said, if you need portability between BSD sockets and Winsock,it’s much easier to rewrite a program usingread() and suchwith sockets to use portable functions likerecv() than it is toarm-twist the Windows port to work with Unix idioms.

Winsock’sclosesocket() vs. Unix’sclose()

Winsock defines a different function for closing sockets becausenot all versions of Windows have file descriptor and socket descriptorequivalency like Unix. See the discussion in the previous item formore on the file/socket handle mismatch issue.

Winsock’sioctlsocket() vs. Unix’sioctl()

Unix provides theioctl() call to allow you to set and getvarious bits of info on a file descriptor, which includes socketdescriptors. Winsock replicates some common Unix ioctls in theioctlsocket() call, but much is missing.

If you use theSIOCGIFCONF ioctl on Unix toget information about the system’s network interfaces,Winsock 2 provides very similar functionality with itsSIO_GET_INTERFACE_LIST option forioctlsocket().

fcntl()

The Unixfcntl() call has no direct equivalentunder Winsock. Where necessary, similar functionality existsin Winsock’sioctlsocket() call. For example, theequivalent of using Unix’sfcntl() to set a socket’sO_NONBLOCK flag is setting theFIONBIO flag withWinsock’sioctlsocket().

poll()

There are several wrappers forpoll() usingselect() out there.Here’sone. It doesn’t attempt to implement any of the specialpoll() features found in a true System V system, such asSTREAMS support. Also, the code is rather old, written in a K&RC style that some newer compilers might reject. Finally, sinceit is built directly on top ofselect(), it has the samelimitations.

Another option is to dig the implementationofpoll() out of Jarle Aasa’sWin32 port of the adnslibrary. This implementation has three limitations: 1) It’sGPL’d, whichmeans you can’t use the code in your program unless your programis also licensed under the GPL; 2) it’s built on the Win32 eventobject mechanism, which has ahard64-object limitation; and 3) it is reportedly not written in away that is easy for third-party programmers to extract and use.

readv() andwritev()

Winsock 2’s overlapped I/O mechanism includes scatter/gatherfunctionality similar to that provided byreadv() andwritev().

dup()

The Unixdup() function duplicates a file handle, andof course also works for sockets. Under Winsock 2, you can do thesame thing withWSADuplicateSocket(). It’s a bit moreinvolved, but theWSADuplicateSocket() documentation inMSDN has a good step-by-stepexample showing how to use this mechansim.

dup2()

There is partial support for this feature under Winsock, though themechanism is dissimilar to thedup2() feature. Under Unix,dup2() takes a handle and duplicates it likedup() does, butwith a twist: it assigns the new file handle a value that you specify.This is usually used to map a socket to the C language’s stdin orstdout file descriptors so that you can use standard I/O functions likeprintf() andfgets() with the socket.

ItemKB190351 in the Microsoft Knowledge Base documentsa method by which you can redirect a child process’s standarddescriptors to a socket. The limitations are that you cannot dothis to your own process’s descriptors, you cannot redirectarbitrary descriptors to a socket (i.e. you can only do it withstdin, stdout and stderr), and not all processes are fully compatiblewith this API feature. Still, it at least makes an inetd-like programpossible under Win32.

Detecting a Dropped Connection

Under BSD Unixes, if the remote peer closes its connectionand your program is blocking onrecv(), you will geta 0 back fromrecv(). Winsock behaves the same way,except that it can also return -1, withWSAGetLastError()returningWSAECONNRESET,WSAECONNABORTEDorWSAESHUTDOWN, to signal the detectable flavors ofabnormal disconnections.

Under Unix, if you’re blocking onsend() and yourprogram is ignoring theSIGPIPE signal, it will returnwith a -1 when the remote peer disconnects, anderrno willbeEPIPE. Otherwise, your program will be sent the SIGPIPEsignal, which will terminate your program if you don’t handleit. Under Winsock, the SIGPIPE/EPIPE functionality does not exist atall:send() will either return 0 for a normal disconnect or -1for an abnormal disconnect, withWSAGetLastError() returningthe same errors as in therecv() discussion above.

UDP Behavior

According to Ilpo Ruotsalainen, "...most BSD socket implementationsdo not pass delayed UDP errors (ICMP port unreachable at least, maybeothers too) torecvfrom() while Winsock 2 [under Windows 2000but not Windows 98] does. Linux [behaves like Windows 2000] too,but provives SO_BSDCOMPATsetsockopt() for being compatiblewith the BSD style."

In other words, a portable program has to be prepared forthe possibility of error codes for non-immediate problems fromrecvfrom(), but it can’t depend on receiving them.


<< The Straight Dope on Packet Sniffers
WsControl() Revealed >>

This article is copyright © 1998-2016by Warren Young, all rights reserved.

Updated Fri Dec 16 2022 12:23 MST Go to my home page

[8]ページ先頭

©2009-2026 Movatter.jp