现在的位置: 首页 > 综合 > 正文

【Linux 编程】网络套接字

2012年04月30日 ⁄ 综合 ⁄ 共 3214字 ⁄ 字号 评论关闭

  1. 基本操作

  套接子是通信端点的抽象。套接字描述符作为套接字的标识符,它是以一种文件形式存在的。如果通信端点是一个“人”,那么套接字标识符就是人的“身份证”。

 

  函数socket()用来创建一个套接字,并获得套接字描述符

1 #include <sys/socket.h>
2 int socket(int domain, int type, int procotol);
3         // 成功返回套接字描述符;出错返回-1

  其中,参数domain确定通信特征,它包括AF_INET,AF_INET6,AF_UNIX;

  参数type确定套接字的类型:

  • SOCK_DGRAM:是长度固定的、无连接的不可靠报文传递。
  • SOCK_STREAM:是有序、可靠、双向的面向连接字节流。作为字节流服务,需要数据读取一端不停读取数据,直到传递一端关闭或自定义结束符。
  • SOCK_RAW:该套接字提供了一个数据报接口用于直接访问网络层(即IP协议层),不经过传输层(即TCP协议栈)。应用程序需要负责构建需要的协议首部信息。

 

  由于套接字是双向的,函数shutdown()用来禁止套接字上的输出/输入

1 #include <sys/socket.h>
2 int shutdown(int sockfd, int how);
3             // 成功返回0;若出错返回-1

  其中,how用来表示关闭方式,包括以下几种:

  • SHUT_RD(关闭读端),则无法从套接字中读取数据;
  • SHUT_WR(关闭写端),则无法使用套接字发送数据;
  • SHUT_RDWR(关闭读写),则无法同时读取和发送数据。

  使用shutdown代替close来关闭套接的好处:首先,close只有在最后一个活动引用被关闭时才释放网络端点。而shutdown可以强制使一个套接字处于不活动状态,无论他的文件描述符数目是多少。并且使用shutdown可以关闭单方向的数据传输,或双方向的数据传输。

 

  函数bind()将地址绑定到一个套接字

1 #include <sys/socket.h>
2 int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
3             // 成功返回0;出错返回-1

  函数getsockname用来获取绑定到sockfd上的套接字。

  若套接字已和对方链接上,则函数getpeername来获取对方的地址。

 

  如果处理的是面向连接的网络服务(SOCK_STREAM或SOCK_SEQPACKET),在开始交换数据之前,需要在请求服务的进程套接字和提供服务的进程套接字之间建立一个逻辑连接。函数connect()提供了这个功能,建立一个连接

1 #include <sys/socket.h>
2 int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
3             // 成功返回0;错误返回-1

  其中,若sockfd没有绑定到一个地址上,connect会将其绑定到一个默认地址上。

  

  服务器端用listen()函数来监听套接字上的连接

#include <sys/socket.h>
int listen(int sockfd, int backlog);
            // 成功返回0;出错返回-1

  其中,参数backlog用于表示该进程所要入队的连接请求的数量。一旦队列满,系统会拒绝多的连接请求。

 

  一旦服务器调用了listen监听指定的地址,套接字就能通过函数accept来获取请求并建立连接

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr* addr, socklen_t *len);
    // 若成功返回文件(套接字)描述符;若出错返回-1。

  

  2. 数据传输 

  1)发送数据的三个函数,并且三个函数在发送成功时均返回发送的字节数;若出错则返回-1

  • send函数。
    1 #include <sys/socket.h>
    2 ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);

    其中,对于支持位报文设限的协议,如果单个报文超过协议所支持的最大尺寸,send()函数失败定将errno设置为EMSGSIZE;对于字节流协议,send()函数将阻塞直到整个数据被传输完毕。

  • sendto函数,该函数允许在无连接的套接字上指定一个目标地址。
    #include <sys/socket.h>
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
  • sendmsg函数,可以指定多重缓冲区来传输数据。
    #include <sys/socket.h>
    ssize_t sendmsg(int sockfd, const struct msgaddr* msg, int flags)

  2) 接收数据的三个函数,并三个函数成功时返回以字节计数的消息长度;若无可用消息或对方已经按序结束并返回则返回0;若出错则返回-1

  • recv函数,从指定套接字上接收消息,用选项来控制如何接收数据。
    #include <sys/socket.h>
    ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
  • recvfrom函数,不仅完成函数recv功能,还能获取数据发送者的源地址。
    #include <sys/socket.h>
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
      struct sockaddr* src_addr, socklen_t *addrlen);
  • recvmsg函数,可以将接收到的数据送入多个缓冲区,或者可以接收辅助数据。
    #include <sys/socket.h>
    ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

     

  3. 套接字选项

  套接字机制提供套接字选项接口来控制套接字行为,但仅支持获取或设置下面三种选项:

  • 通用选项,工作在所有套接字类型上;
  • 在套接字层次管理的选项,但是依赖于下层协议的支持;
  • 特定于某协议的选项,为每个协议所独有

  

  函数getsockopt()用来获取当前套接字的选项

#include <sys/socket.h>
int getsockopt(int sockfd, int level, int option, void *val, socklen_t *len);
            // 成功返回0;出错则返回-1

  函数setsockopt()用来设置套接字的选项

#include <sys/socket.h>
int setsockopt(int sockfd, int level, int option, const void *val, socklen_t len);
            // 成功返回0;失败则返回-1。

 

  4. 非阻塞和异步I/O

  recv函数在没有数据可用时会阻塞等待,而send函数会在数据队列已满的情况下阻塞等待。若将函数设置为非阻塞状态,则函数在需要阻塞时失败返回,并将errno设置为EWOULDBLOCK或EAGAIN。当这些情况发生时,可以使用poll、select或epoll来判断何时接收或发送数据。

 

  在基于套接字的异步I/O中,当能够从套接字中读取数据,或套接字写队列中有空间可用时,可以发送信号SIGIO。通过两个步骤来使用异步I/O:

  • 确立套接字拥有者关系,信号可以被传递到合适的进程:
    在fcntl使用F_SETOWN命令。
  • 当I/O操作不会阻塞时发送信号告知套接字:
    在fcntl使用F_SETFL命令比并启动文件标志O_ASYNC。

 

 

 

 

抱歉!评论已关闭.