linux 中socket

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.

 

转载于:https://my.oschina.net/u/2326611/blog/848598

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值