网络编程之socket常用接口

网络编程中,socket是基础,理解socket的常用接口及其参数也成为网络编程的入门课。常用接口包括:

       创建   socket bind listen accept connect
       收发   read/recv/recvfrom  write/send/sendto   
       关闭   close shutdown
       参数   getsockopt/setsockopt
       地址   gethostbyaddr getaddrbyhost,结构体 sockaddr

       获取本端或对端的地址 getsockname、getpeername

  • socket

#include <sys/socket.h>

int socket(int domain, int type, int protocol)

若成功返回0,出错返回-1

domain  指定通信的特性。POSIX指定的域包括AF_NET(IPV4因特网)、AF_NET6(IPV6因特网)、AF_UNIX(UNIX域)、AF_UNSPEC(未指定)。多数系统还会定义AF_LOCAL域,这是AF_UNIX的别名。

type        指定套接字的类型。POSIX定义的套接字的类型包括SOCK_DGRAM(长期固定的、无连接的不可靠报文传递)、SOCK_RAW(IP协议的数据报接口)、SOCK_SEQPACKET(长度固定、有序、可靠的面向链接的协议)、SOCK_STREAM(有序、可靠、双向的面向链接字节流)。

protocol  通常为0,表示按照给定的域和套接字类型选择默认协议。在AF_NET协议域中,SOCK_DGREM默认协议是UDP协议(用户数据报协议),SOCK_STREAM默认协议是TCP协议(传输控制协议)。

注:UDP协议与对方通信是不需要逻辑链接的。只需要送出一个报文,其地址是一个对方进程所使用的套接字。

  • bind

#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr* addr, socklen_t len)

若成功返回0,出错返回-1

该函数用于服务器端绑定一个周所知的地址,便于客户端进行链接通信。

对于因特网域,如果对指定IP地址为INADDR_ANY,套接字端口可以绑定到服务器上的所有网络接口。一般对于多网卡侦听的服务器,可以设置器服务地址为INADDR_ANY,这样对于多网卡都可以接收客户端请求。多网卡在解决网络IO导致的服务器性能瓶颈问题中算是一个解决方案

  • getsockname

#include <sys/socket.h>

int getsockname(int sockfd, struct sockaddr* restrict addr, socklen_t* restrict alenp) 

若成功返回0,出错返回-1

在调用getsockname之前,设置alenp为一个指向整数的指针,该整数指定缓冲区sockaddr的大小。返回时,该整数会被设置成返回地址的大小。如果该地址和提供的缓冲区的长度不匹配,则将其截断而不报错。如果当前没有绑定到该套接字的地址,结果未定义。

  • getpeername

#include <sys/socket.h>

int getpeername(int sockfd, struct sockaddr* restrict addr, socklen_t*restict alenp)

若成功返回0,出错返回-1

用法同getsockname

  • listen

#include <sys/socket.h>

int listen(int sockfd, int backlog)

若成功返回0,出错返回-1

backlog表示该进程要求入队列的连接请求数目。其实际值由系统决定,但是上限在<sys/socket.h>中SOMAXCONN指定。Linux下TCP为128。

一旦队列满,系统会拒绝多余的连接请求,所以backlog应该基于服务器期望负载和接收连接请求与启动服务的处理能力来选择。

  • accept

#include <sys/scoket.h>

int accept(int sockfd, struct sockaddr* restrict addr, socklen_t* restrict alenp)

若成功返回文件(套接字)描述符,出错返回-1

sockfd参数为listen指定的侦听套接字,这个套接字不会关联到客户端connect的套接字,而是继续进行侦听接收其它连接请求。

如果不关心客户端标识,可以将参数addr和alenp设置为NULL;如果参数addr和alenp非NULL,则accept成功后,addr指向的缓冲区保存客户端的标识信息。

注:如果没有链接请求,accept会阻塞直到一个请求到来。如果sockfd处于非阻塞模式,accept会返回-1,error设置为EAGAIN或EWOULDBLOCK。accept成功后,如果客户端往连接套接字中写入数据,则服务器端对应的套接字的事件为可读。

  • connect

#include <sys/socket.h>

int connect(int sockfd, const struct  sockaddr* addr, socklen_t len)

若成功返回0,出错返回-1

如果sockfd没有绑定到一个地址,则connect会给调用者绑定一个地址。这是一般的客户端的用法。

connect可能的出错原因:服务没有启动,服务等待队列空间不足。因此需要对connect的返回错误进行处理。

如果套接字出于非阻塞模式下,链接不能马上建立时,connect将会返回-1,并且将error设置为EINPROGRESS。应用可以使用poll或select或epoll判断文件描述符何时可写。如果可写,连接完成。

注:connect成功后,sockfd的事件为可写。

connect还可以用于SOCK_DGRAM,实际上并未建立连接,只是在以后每次传送报文时不需要再提供地址。另外仅能接收来至指定地址的报文。仅此而已。

  • send

#include <sys/socket.h>

ssize_t send(int sockfd, const void* buf, size_t nbytes, int flags)

若成功则返回发送的字节数,若出错则返回-1

send和write很像,但是可以指定标志来改变处理传输数据的方式。send支持四个标志:

MSG_DONTROUTE 

MSG_DONTWAIT         允许非阻塞操作,相当于使用O_NONBLOCK

MSG_EOR

MSG_OOB                     发送带外数据

注:send成功返回,并不表示对端进程接收数据,只表示本端将数据正确发到网络上。对于字节流协议,send会阻塞知道所有数据传输完毕。

  • sendto

#include <sys/socket.h>

ssize_t sendto(int sockfd, cosnt void* buf, size_t nbytes, int  flags, const struct sockaddr*destaddr, socklen_t destlen)

若成功则返回发送的字节数,若出错则返回-1

sendto和send类似,区别在域sendto允许在无连接的套接字上指定一个目标地址。

  • sendmsg

#include <sys/socket.h>

ssize_t sendmsg(int sockfd, const struct msghdr*msg, int flags)

若成功返回发送的字节数,若出错则返回-1

  • recv

#include <sys/socket.h>

ssize_t recv(int sockfd, void*buf, size_t nbytes, int flags)

返回值:以字节计数的消息长度,若无可用的消息或对方已经按序结束则返回0,若出错则返回-1

recv和read很像,但是允许指定选项来控制如何接收数据。

MSG_OOB        接收带外数据

MSG_PEEK      返回报文内容,只是查看,而不真正取走报文。再次调用read或者recv的时候才取走数据。

MSG_TRUNC   即使报文被截断,要求返回的是报文的实际长度

MSG_WAITALL 直到所有的数据可用(仅SOCK_STREAM)

注:如果发送者已经调用shutdown关闭,或者发送端已经关闭,那么当所有的数据接收完毕后,recv返回0。

  • recvfrom

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void*buf, size_t nbytes, int flags, struct sockaddr* restrict addr, socklen_t* restrict alenp)

返回值:以字节计数的消息长度,若无可用的消息或对方已经按序结束则返回0,若出错则返回-1

recvfrom和recv很像,不同之处是可以用于定位发送者,如果addr和alenp不为NULL,则保存发送者地址信息。

  • recvmsg

#include <sys/socket.h>

ssize_t recvmsg(int sockfd, void*buf, size_t nbytes, int flags, struct sockaddr* restrict addr, socklen_t* restrict alenp)

  • read

#include <unistd.h>

ssize_t read(int filedes, void* buf, size_t nbyes)

返回值:若成功,返回读到的字节数,若已经到文件结尾则返回0,若出错则返回-1

当从网络读时,网络中的缓冲机制可能造成返回值小于所要求的字节数。

  • write

#include <unistd.h>

ssize_t write(int filedes, const void*buf, size_t nbytes)

返回值:若成功,返回已写的字节数,若出错则返回-1

  • setsockopt

#include <sys/socket.h>

int setsockopt(int sockfd, int level, int option, const void* val, socklen_t len)

返回值:若设置成功返回0,若出错则返回-1

level 标识选项应用的协议,如果选择通用的套接字层选项,level设置成SOL_SOCKET;否则,level是设置成控制这个选项的协议号。

val    根据选项不同指向一个数据结构或者一个整数。一些选项是on/off开关。

len    指定了val指向的对象的大小。

  • getsockopt

#include <sys/socket.h>

int getsockopt(int sockfd, int level, int option, const void* val, socklen_t* lenp)

返回值:若设置成功返回0,若出错则返回-1
lenp是一个指向整数的指针。在调用getsockopt之前,设置该整数为复制选项缓冲区的大小。
通用套接字选项,level为SO_SOCKET:
SO_ACCEPTCONN        int       返回该套接字是否可以侦听(仅getsockopt)
SO_BROADCAST            int       如果*val非零,广播数据包
SO_DEBUG                      int       如果*val非零,启用网络驱动调试功能
SO_BONTROUTE           int       如果*val非零,绕过通常路由
SO_ERROR                     int       返回挂起的套接字错误并清除(仅getsockopt)
SO_KEEPALIVE              int       如果*val非零,启用周期性keep-alive消息
SO_LINGER                struct linger 当有未发送消息,并且套接字关闭的时候,延迟时间
SO_OOBINLINE              int       如果*val非零,将带外数据放在普通数据中
SO_RCVBUF                   int        以字节为单位的接收缓存的大小
SO_RCVLOWAT              int        接受调用中返回的以字节为单位的最小数据量
SO_RCVTIMEO          struct timeval  套接字接受调用的超时时间
SO_REUSEADDR          int        如果*val非零,重用bind中的地址。注: 如果*val为零,在服务进程重启时,由于存在未释放的连接,bind会失败。因此,出于运维考虑,一般该选项设置为非零
SO_SNDBUF                   int        以字节为单位的发送缓存的大小
SO_SNDLOWAT             int        发送调用中以字节为单位的发送最小数据量
SO_SNDTIMEO          struct timeval  套接字发送调用的超时时间
SO_TYPE                         int        套接字类型(仅getsockopt)

  • shutdown
#include <sys/socket.h>
int shutdown(int sockfd, int how)
返回值:若成功则返回0,若出错则返回-1
how SHUT_RD,关闭读端,那么无法从套接字读取数据;SHUT_WR,关闭写端,无法使用套接字发送数据;SHUT_RDWR,同时无法使用套接字进行读取或发送数据。
shutdown和close的区别:
1、close,只有在最后一个活动引用被关闭时才释放网络端点。如果复制了一个套接字,只有在关闭了最后一个引用它的文件描述符后,才会被释放。而shutdown允许使一个套接字处于不活动状态,无论引用它的文件描述符有多少;
2、shutdown允许只关闭连接双向中的一个方向。例如,如果想让所通信的进程能够确定数据发送何时结束,可以关闭该套接字的写端,然而通过该套接字读端仍可以接收数据;

  • close

#include <unistd.h>

int close(int filedes)

返回值:若成功则返回0,若出错则返回-1

注:关闭一个文件描述符,系统并不一定马上释放该文件描述符对应的资源,只有在关闭了最后一个引用后才释放。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值