socket
参考:
http://www.cnblogs.com/wmx-learn/p/5312259.html
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议,而不需要让用户自己去定义什么时候需要指定哪个协议哪个函数。
一、针对套接字的系统数据结构:
1)、套接字API里有个函数socket,它就是用来创建一个套接字。套接字设计的总体思路是,单个系统调用就可以创建任何套接字,因为套接字是相当笼统的。一旦套接字创建后,应用程序还需要调用其他函数来指定具体细节。例如调用socket将创建一个新的描述符条目:
2)、虽然套接字的内部数据结构包含很多字段,但是系统创建套接字后,大多数字字段没有填写。应用程序创建套接字后在该套接字可以使用之前,必须调用其他的过程来填充这些字段。
二、基本的socket接口函数
服务器端先初始化/创建Socket,然后与端口绑定/绑定地址(bind),对端口进行监听(listen),调用accept阻塞/等待连续,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
2.1socket函数
NAME
socket - create an endpoint for communication
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
DESCRIPTION
socket() creates an endpoint for communication and returns a descriptor.
The domain argument specifies a communication domain; this selects the protocol family which will be used for communication. These families are defined in
<sys/socket.h>. The currently understood formats include:
Name Purpose Man page
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX - Novell protocols
AF_NETLINK Kernel user interface device netlink(7)
AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)
AF_AX25 Amateur radio AX.25 protocol
AF_ATMPVC Access to raw ATM PVCs
AF_APPLETALK Appletalk ddp(7)
AF_PACKET Low level packet interface packet(7)
The socket has the indicated type, which specifies the communication semantics. Currently defined types are:
SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be supported.
SOCK_DGRAM Supports datagrams (connectionless, unreliable messages of a fixed maximum length).
SOCK_SEQPACKET Provides a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is required to
read an entire packet with each input system call.
SOCK_RAW Provides raw network protocol access.
SOCK_RDM Provides a reliable datagram layer that does not guarantee ordering.
SOCK_PACKET Obsolete and should not be used in new programs; see packet(7).
Some socket types may not be implemented by all protocol families; for example, SOCK_SEQPACKET is not implemented for AF_INET.
Since Linux 2.6.27, the type argument serves a second purpose: in addition to specifying a socket type, it may include the bitwise OR of any of the following val-
ues, to modify the behavior of socket():
SOCK_NONBLOCK Set the O_NONBLOCK file status flag on the new open file description. Using this flag saves extra calls to fcntl(2) to achieve the same result.
SOCK_CLOEXEC Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor. See the description of the O_CLOEXEC flag in open(2) for reasons why this may
be useful.
The protocol specifies a particular protocol to be used with the socket. Normally only a single protocol exists to support a particular socket type within a given
protocol family, in which case protocol can be specified as 0. However, it is possible that many protocols may exist, in which case a particular protocol must be
specified in this manner. The protocol number to use is specific to the “communication domain” in which communication is to take place; see protocols(5). See
getprotoent(3) on how to map protocol name strings to protocol numbers.
Sockets of type SOCK_STREAM are full-duplex byte streams, similar to pipes. They do not preserve record boundaries. A stream socket must be in a connected state
before any data may be sent or received on it. A connection to another socket is created with a connect(2) call. Once connected, data may be transferred using
read(2) and write(2) calls or some variant of the send(2) and recv(2) calls. When a session has been completed a close(2) may be performed. Out-of-band data may
also be transmitted as described in send(2) and received as described in recv(2).
The communications protocols which implement a SOCK_STREAM ensure that data is not lost or duplicated. If a piece of data for which the peer protocol has buffer
space cannot be successfully transmitted within a reasonable length of time, then the connection is considered to be dead. When SO_KEEPALIVE is enabled on the
socket the protocol checks in a protocol-specific manner if the other end is still alive. A SIGPIPE signal is raised if a process sends or receives on a broken
stream; this causes naive processes, which do not handle the signal, to exit. SOCK_SEQPACKET sockets employ the same system calls as SOCK_STREAM sockets. The
only difference is that read(2) calls will return only the amount of data requested, and any data remaining in the arriving packet will be discarded. Also all
message boundaries in incoming datagrams are preserved.
SOCK_DGRAM and SOCK_RAW sockets allow sending of datagrams to correspondents named in sendto(2) calls. Datagrams are generally received with recvfrom(2), which
returns the next datagram along with the address of its sender.
SOCK_PACKET is an obsolete socket type to receive raw packets directly from the device driver. Use packet(7) instead.
An fcntl(2) F_SETOWN operation can be used to specify a process or process group to receive a SIGURG signal when the out-of-band data arrives or SIGPIPE signal
when a SOCK_STREAM connection breaks unexpectedly. This operation may also be used to set the process or process group that receives the I/O and asynchronous
notification of I/O events via SIGIO. Using F_SETOWN is equivalent to an ioctl(2) call with the FIOSETOWN or SIOCSPGRP argument.
When the network signals an error condition to the protocol module (e.g., using a ICMP message for IP) the pending error flag is set for the socket. The next
operation on this socket will return the error code of the pending error. For some protocols it is possible to enable a per-socket error queue to retrieve
detailed information about the error; see IP_RECVERR in ip(7).
The operation of sockets is controlled by socket level options. These options are defined in <sys/socket.h>. The functions setsockopt(2) and getsockopt(2) are
used to set and get options, respectively.
RETURN VALUE
On success, a file descriptor for the new socket is returned. On error, -1 is returned, and errno is set appropriately.
2.2bind()函数
man 2 bind
NAME
bind - bind a name to a socket
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
DESCRIPTION
When a socket is created with socket(2), it exists in a name space (address family) but has no address assigned to it. bind() assigns the address specified to by
addr to the socket referred to by the file descriptor sockfd. addrlen specifies the size, in bytes, of the address structure pointed to by addr. Traditionally,
this operation is called “assigning a name to a socket”.
It is normally necessary to assign a local address using bind() before a SOCK_STREAM socket may receive connections (see accept(2)).
The rules used in name binding vary between address families. Consult the manual entries in Section 7 for detailed information. For AF_INET see ip(7), for
AF_INET6 see ipv6(7), for AF_UNIX see unix(7), for AF_APPLETALK see ddp(7), for AF_PACKET see packet(7), for AF_X25 see x25(7) and for AF_NETLINK see netlink(7).
The actual structure passed for the addr argument will depend on the address family. The sockaddr structure is defined as something like:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
The only purpose of this structure is to cast the structure pointer passed in addr in order to avoid compiler warnings. See EXAMPLE below.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
ERRORS
EACCES The address is protected, and the user is not the superuser.
EADDRINUSE
The given address is already in use.
EBADF sockfd is not a valid descriptor.
EINVAL The socket is already bound to an address.
ENOTSOCK
sockfd is a descriptor for a file, not a socket.
The following errors are specific to Unix domain (AF_UNIX) sockets:
EACCES Search permission is denied on a component of the path prefix. (See also path_resolution(7).)
EADDRNOTAVAIL
A nonexistent interface was requested or the requested address was not local.
EFAULT addr points outside the user’s accessible address space.
EINVAL The addrlen is wrong, or the socket was not in the AF_UNIX family.
ELOOP Too many symbolic links were encountered in resolving addr.
ENAMETOOLONG
addr is too long.
ENOENT The file does not exist.
ENOMEM Insufficient kernel memory was available.
ENOTDIR
A component of the path prefix is not a directory.
EROFS The socket inode would reside on a read-only file system.
CONFORMING TO
SVr4, 4.4BSD, POSIX.1-2001 (bind() first appeared in 4.2BSD).
NOTES
POSIX.1-2001 does not require the inclusion of <sys/types.h>, and this header file is not required on Linux. However, some historical (BSD) implementations
required this header file, and portable applications are probably wise to include it.
The third argument of bind() is in reality an int (and this is what 4.x BSD and libc4 and libc5 have). Some POSIX confusion resulted in the present socklen_t,
also used by glibc. See also accept(2).
BUGS
The transparent proxy options are not described.
EXAMPLE
An example of the use of bind() with Internet domain sockets can be found in getaddrinfo(3).
The following example shows how to bind a stream socket in the Unix (AF_UNIX) domain, and accept connections:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MY_SOCK_PATH "/somepath"
#define LISTEN_BACKLOG 50
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
int sfd, cfd;
struct sockaddr_un my_addr, peer_addr;
socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
/* Clear structure */
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH,
sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr,
sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
/* Now we can accept incoming connections one
at a time using accept(2) */
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr,
&peer_addr_size);
if (cfd == -1)
handle_error("accept");
/* Code to deal with incoming connection(s)... */
/* When no longer required, the socket pathname, MY_SOCK_PATH
should be deleted using unlink(2) or remove(3) */
}
2.3、listen()、connect()函数
如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
NAME
listen - listen for connections on a socket
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
DESCRIPTION
listen() marks the socket referred to by sockfd as a passive socket, that is, as a socket that will be used to accept incoming connection requests using accept(2).
The sockfd argument is a file descriptor that refers to a socket of type SOCK_STREAM or SOCK_SEQPACKET.
The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow. If a connection request arrives when the queue is
full, the client may receive an error with an indication of ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be ignored so that
a later reattempt at connection succeeds.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
ERRORS
EADDRINUSE
Another socket is already listening on the same port.
EBADF The argument sockfd is not a valid descriptor.
ENOTSOCK
The argument sockfd is not a socket.
EOPNOTSUPP
The socket is not of a type that supports the listen() operation.
CONFORMING TO
4.4BSD, POSIX.1-2001. The listen() function call first appeared in 4.2BSD.
NOTES
To accept connections, the following steps are performed:
1. A socket is created with socket(2).
2. The socket is bound to a local address using bind(2), so that other sockets may be connect(2)ed to it.
3. A willingness to accept incoming connections and a queue limit for incoming connections are specified with listen().
4. Connections are accepted with accept(2).
POSIX.1-2001 does not require the inclusion of <sys/types.h>, and this header file is not required on Linux. However, some historical (BSD) implementations
required this header file, and portable applications are probably wise to include it.
The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely established sockets waiting to be
accepted, instead of the number of incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using
/proc/sys/net/ipv4/tcp_max_syn_backlog. When syncookies are enabled there is no logical maximum length and this setting is ignored. See tcp(7) for more informa-
tion.
If the backlog argument is greater than the value in /proc/sys/net/core/somaxconn, then it is silently truncated to that value; the default value in this file is
128. In kernels before 2.4.25, this limit was a hard coded value, SOMAXCONN, with the value 128.
EXAMPLE
See bind(2).
NAME
connect - initiate a connection on a socket
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
DESCRIPTION
The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr. The addrlen argument specifies the size
of addr. The format of the address in addr is determined by the address space of the socket sockfd; see socket(2) for further details.
If the socket sockfd is of type SOCK_DGRAM then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received.
If the socket is of type SOCK_STREAM or SOCK_SEQPACKET, this call attempts to make a connection to the socket that is bound to the address specified by addr.
Generally, connection-based protocol sockets may successfully connect() only once; connectionless protocol sockets may use connect() multiple times to change their
association. Connectionless sockets may dissolve the association by connecting to an address with the sa_family member of sockaddr set to AF_UNSPEC (supported on
Linux since kernel 2.2).
RETURN VALUE
If the connection or binding succeeds, zero is returned. On error, -1 is returned, and errno is set appropriately.
ERRORS
The following are general socket errors only. There may be other domain-specific error codes.
EACCES For Unix domain sockets, which are identified by pathname: Write permission is denied on the socket file, or search permission is denied for one of the
directories in the path prefix. (See also path_resolution(7).)
EACCES, EPERM
The user tried to connect to a broadcast address without having the socket broadcast flag enabled or the connection request failed because of a local fire-
wall rule.
EADDRINUSE
Local address is already in use
EAFNOSUPPORT
The passed address didn’t have the correct address family in its sa_family field.
EADDRNOTAVAIL
Non-existent interface was requested or the requested address was not local.
EALREADY
The socket is non-blocking and a previous connection attempt has not yet been completed.
EBADF The file descriptor is not a valid index in the descriptor table.
ECONNREFUSED
No-one listening on the remote address.
EFAULT The socket structure address is outside the user’s address space.
EINPROGRESS
The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the
socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect()
completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
EINTR The system call was interrupted by a signal that was caught; see signal(7).
EISCONN
The socket is already connected.
ENETUNREACH
Network is unreachable.
ENOTSOCK
The file descriptor is not associated with a socket.
ETIMEDOUT
Timeout while attempting connection. The server may be too busy to accept new connections. Note that for IP sockets the timeout may be very long when syn-
cookies are enabled on the server.
2.4、accept()函数
NAME
accept - accept a connection on a socket
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE
#include <sys/socket.h>
int accept4(int sockfd, struct sockaddr *addr,
socklen_t *addrlen, int flags);
DESCRIPTION
The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection request on the queue of pend-
ing connections for the listening socket, sockfd, creates a new connected socket, and returns a new file descriptor referring to that socket. The newly created
socket is not in the listening state. The original socket sockfd is unaffected by this call.
The argument sockfd is a socket that has been created with socket(2), bound to a local address with bind(2), and is listening for connections after a listen(2).
The argument addr is a pointer to a sockaddr structure. This structure is filled in with the address of the peer socket, as known to the communications layer.
The exact format of the address returned addr is determined by the socket’s address family (see socket(2) and the respective protocol man pages). When addr is
NULL, nothing is filled in; in this case, addrlen is not used, and should also be NULL.
The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; on return it
will contain the actual size of the peer address.
The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.
If no pending connections are present on the queue, and the socket is not marked as non-blocking, accept() blocks the caller until a connection is present. If the
socket is marked non-blocking and no pending connections are present on the queue, accept() fails with the error EAGAIN or EWOULDBLOCK.
In order to be notified of incoming connections on a socket, you can use select(2) or poll(2). A readable event will be delivered when a new connection is
attempted and you may then call accept() to get a socket for that connection. Alternatively, you can set the socket to deliver SIGIO when activity occurs on a
socket; see socket(7) for details.
For certain protocols which require an explicit confirmation, such as DECNet, accept() can be thought of as merely dequeuing the next connection request and not
implying confirmation. Confirmation can be implied by a normal read or write on the new file descriptor, and rejection can be implied by closing the new socket.
Currently only DECNet has these semantics on Linux.
If flags is 0, then accept4() is the same as accept(). The following values can be bitwise ORed in flags to obtain different behavior:
SOCK_NONBLOCK Set the O_NONBLOCK file status flag on the new open file description. Using this flag saves extra calls to fcntl(2) to achieve the same result.
SOCK_CLOEXEC Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor. See the description of the O_CLOEXEC flag in open(2) for reasons why this may
be useful.
RETURN VALUE
On success, these system calls return a non-negative integer that is a descriptor for the accepted socket. On error, -1 is returned, and errno is set appropri-
ately.
Error Handling
Linux accept() (and accept4()) passes already-pending network errors on the new socket as an error code from accept(). This behavior differs from other BSD socket
implementations. For reliable operation the application should detect the network errors defined for the protocol after accept() and treat them like EAGAIN by
retrying. In case of TCP/IP these are ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and ENETUNREACH.
ERRORS
EAGAIN or EWOULDBLOCK
The socket is marked non-blocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does
not require these constants to have the same value, so a portable application should check for both possibilities.
EBADF The descriptor is invalid.
ECONNABORTED
A connection has been aborted.
EFAULT The addr argument is not in a writable part of the user address space.
EINTR The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7).
EINVAL Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
EINVAL (accept4()) invalid value in flags.
EMFILE The per-process limit of open file descriptors has been reached.
ENFILE The system limit on the total number of open files has been reached.
ENOBUFS, ENOMEM
Not enough free memory. This often means that the memory allocation is limited by the socket buffer limits, not by the system memory.
ENOTSOCK
The descriptor references a file, not a socket.
EOPNOTSUPP
The referenced socket is not of type SOCK_STREAM.
EPROTO Protocol error.
In addition, Linux accept() may fail if:
EPERM Firewall rules forbid connection.
In addition, network errors for the new socket and as defined for the protocol may be returned. Various Linux kernels can return other errors such as ENOSR,
ESOCKTNOSUPPORT, EPROTONOSUPPORT, ETIMEDOUT. The value ERESTARTSYS may be seen during a trace.