转载: http://wiki.treck.com/Introduction_to_BSD_Sockets
The Berkeley Sockets 4.4 API (Applications Programmer Interface) is a set of standard function calls made available at the application level. These functions allow programmers to include Internet communications capabilities in their products.
The Berkeley Sockets API (also frequently referred to as simply `sockets') was originally released with 4.2BSD in 1983. Enhancements have continued through the 4.4BSD systems. Berkeley-based code can be found in many different operating systems, both commercial and public domain, such as BSD/OS, FreeBSD, NetBSD, OpenBSD, and UnixWare 2.x. Other popular operating systems such as Solaris and Linux employ the standard sockets interface, though the code was written from scratch.
Other sockets APIs exist, though Berkeley Sockets is generally regarded as the standard. Two of the most common APIs are Winsock and TLI. Winsock (Windows Sockets) was developed for the Microsoft Windows platform in 1993, and is based significantly on the BSD interface. A large subset of the BSD API is provided, with most of the exceptions being platform-specific to BSD systems. TLI (Transport Layer Interface) was developed by AT&T, and has the capability to access TCP/IP and IPX/SPX transport layers. XTI (X/Open Transport Interface, developed by X/Open Company Ltd.) is an extension of TLI that allows access to both TCP/IP and NetBios.
Contents[hide] |
Overview of Sockets
BSD Sockets generally relies upon client/server architecture. For TCP communications, one host listens for incoming connection requests. When a request arrives, the server host will accept it, at which point data can be transferred between the hosts. UDP is also allowed to establish a connection, though it is not required. Data can simply be sent to or received from a host.
The Sockets API makes use of two mechanisms to deliver data to the application level: ports and sockets. Ports and sockets are one of the most misunderstood concepts in sockets programming.
All TCP/IP stacks have 65,536 ports for both TCP and UDP. There is a full compliment of ports for UDP (numbered 0-65535) and another full compliment, with the same numbering scheme, for TCP. The two sets do not overlap. Thus, communication over both TCP and UDP can take place on port 15 (for example) at the same time.
A port is not a physical interface - it is a concept that simplifies the concept of Internet communications for humans. Upon receiving a packet, the protocol stack directs it to the specific port. If there is no application listening on that port, the packet is discarded and an error may be returned to the sender. However, applications can create sockets, which allow them to attach to a port. Once an application has created a socket and bound it to a port, data destined to that port will be delivered to the application. This is why the term socket is used - it is the connection mechanism between the outside world (the ports) and the application. A common misunderstanding is that sockets-based systems can only communicate with other sockets-based systems. This is not true. TCP/IP or UDP/IP communications are handled at the port level - the underlying protocols do not care what mechanisms exist above the port. Any Internet host can communicate with any other, be it Berkeley Sockets, WinSock, or anything else. "Sockets" is just an API that allows the programmer to access Internet functionality - it does not modify the manner in which communications occur. Let us use the example of an office building to illustrate how sockets and ports relate to each other. The building itself is analogous to an Internet host. Each office represents a port, the receptionist is a socket, and the business itself is an application. Suppose you are a visitor to this building, looking for a particular business. You wander in, and get directed to the appropriate office. You enter the office, and speak with the receptionist, who then relays your message to the business itself. If there is nobody in the office, you leave. To rephrase the above in sockets terminology: A packet is transmitted to a host. It eventually gets to the correct port, at which point the socket conveys the packet's data to the application. If there is no socket at the destination port, the packet is discarded.
Byte-Ordering Functions
Because TCP/IP has to be a universal standard, allowing communications between any platforms, it is necessary to have a method of arranging information so that big-endian and little-endian machines can understand each other. Thus, there are functions that take the data you give them and return them in network byte-order. On platforms where data is already correctly ordered, the functions do nothing and are frequently macro'd into empty statements. Byte-ordering functions should always be used as they do not impact performance on systems that are already correctly ordered and they promote code portability. The four byte-ordering functions are htons, htonl, ntohs, and ntohl. These stand for host to network short, host to network long, network to host short, and network to host long, respectively. htons translates a short integer from host byte-order to network byte-order. htonl is similar, translating a long integer. The other two functions do the reverse, translating from network byte-order to host byte-order.
Common Socket Calls
This section lists the most commonly used socket calls and describes their uses. This is purely introductory material. For a more complete description of how the calls work, please see the Programmer's Reference.
socket()
A socket, in the simplest sense, is a data structure used by the Sockets API. When the user calls this function, it creates a socket and returns reference a number for that socket. That reference number, in turn, must be used in future calls.
bind()
This call allows a user to associate a socket with a particular local port and IP address. In the case of a server (see listen and accept below), it allows the user to specify which port and IP address incoming connections must be addressed to. For outgoing connection requests (see connect below), it allows the user to specify which port the connection will come from when viewed by the other host.
listen()
This function prepares the given socket to accept incoming TCP requests. It must be called before accept().
accept()
This function detects incoming connection requests on the listening socket. In blocking mode, this call will cause a task to sleep until a connection request is received. In non-blocking mode, this call will return TM_EWOULDBLOCK indicating that no connection request is present and that accept must be called again. If the user calls accept and a connection request is pending, accept creates another socket based on the properties of the listening socket. If the call is successful, the socket descriptor of the newly created and connected socket is returned. The new socket is created to allow communications with multiple clients from a single port on the server (think of web servers, which listen on port 80 by default and are capable of communicating with thousands of hosts at the same time). Each time the user calls accept and there is a connection requests pending, it creates a new socket.
connect()
When a user issues a connect command, the stack creates a connection with another host. Before connect can instruct the stack to establish a connection, the user must pass a socket and a sockaddr_in structure containing the destination IP address and port. In TCP, an actual connection is negotiated. In UDP, however, no packets are exchanged.
send()
This call allows a user to send data over a connected socket. Unlike sendto(), this socket must be connected. Because the socket is already connected, it is not necessary to specify the destination address (the destination address was set inaccept or connect). send can be used for either UDP or TCP data.
sendto()
Unlike send(), sendto requires users to specify the destination port and address. This is useful for UDP communications only, as TCP requires a pre-existing connection. sendto may be used on either connected or unconnected UDP sockets. In the case that a UDP socket is already connected, the destination address provided to sendto will override the default established on the socket with connect.
recv()
This function allows the user to receive data on the connected socket. recv can be used for either TCP or UDP.
recvfrom()
This function allows the user to receive data from a specified UDP socket (whether or not it is connected). It may not be used for TCP sockets, as they require a connection.
close()
This function closes (read: deletes) a socket that has been allocated with the socket call. If the socket is connected, it closes the connection before deleting it. Because the close call is frequently used for more than one purpose (closing open files, for example), it is renamed tfClose() in the Treck stack to avoid conflicts with the preexisting function.