socket - meetbill/x-luo GitHub Wiki
socket 模块
socket 模块
翻译过来称为套接字
是对底层的 TCP IP UDP 等网络协议进行封装
使得上层的应用程序开发者,不用直接接触这复杂,丑陋的协议
对于程序员而言,它就是一个封装好的模块!
要完成网络通讯,只需要使用系统提供的 socket 模块就行
创建套接字 socket 函数的详解
首先放上创建套接字的代码,再具体讲述函数中每一个参数的具体含义:
#include <sys/socket.h>
int socket(int domain,int type,int protocol);
->成功时返回文件描述,失败时返回 -1(linux)
这里有三个参数(以 linux 下为例):
- (1)、domain: 套接字中使用的协议族(Protocol Family)信息;
- (2)、type:套接字数据传输类型信息
- (3)、protocol:计算机间通信中使用的协议信息
domain
其中第一个协议族的信息主要有如下几类,但是常用的是 IPV4 协议族(PF_INET)
PF_INET:IPv4 协议族
PF_INET6:IPv6 协议族
PF_LOCAL: 本地通信的 UNIX 协议族
PF_PACKET: 底层套接字的协议族
PF_IPX:IPX Novell 协议族
AF_INET(又称 PF_INET)是 IPv4 网络协议的套接字类型,AF_INET6 则是 IPv6 的;而 AF_UNIX 则是 Unix 系统本地通信。
type
第二个参数是套接字类型,具有代表性的又两种:
(1)、面向连接的套接字(SOCK_STREAM)
这种类型的特点有:
a、传输过程中数据不丢失
b、按序传输数据(先发先达)
c、传输的数据不存在数据边界
可以总结为:“可靠地、按序传递的、基于字节的面向连接的数据传输方式的套接字”
(2)、面向消息的套接字(SOCK_DGRAM)
这种类型的特点有:
a、强调快速传输而非传输顺序
b、传输数据可能丢失也可能损坏
c、传输的数据有数据边界
d、限制每次传输的数据大小
可以总结为:“不可靠的、不按顺序的、以数据的高速传输为目的的套接字”
protocol
创建 TCP 套接字
# socket.AF_INET 用于服务器与服务器之间的网络通信 (网络连接,ipv4)
# socket.SOCK_STREAM 用于基于 TCP 的流式 socket 通信 (TCP 连接)
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
默认的 socket 选项不够用的时候,就必须要使用 setsockopt 来调整。就是使用 setsockopt。
serversocket.setsockopt(level,optname,value)
有三个参数:
level:选项定义的层次。支持 SOL_SOCKET(常用)、IPPROTO_TCP、IPPROTO_IP 和 IPPROTO_IPV6。
optname:需设置的选项。
value:设置选项的值。
linux 非阻塞的 socket EAGAIN 的错误处理
发送时
当客户通过 Socket 提供的 send 函数发送大的数据包时,就可能返回一个 EAGAIN 的错误。该错误产生的原因是由于 send 函数中的 size 变量大小超过了 tcp_sendspace 的值。tcp_sendspace 定义了应用在调用 send 之前能够在 kernel 中缓存的数据量。当应用程序在 socket 中设置了 O_NDELAY 或者 O_NONBLOCK 属性后,如果发送缓存被占满,send 就会返回 EAGAIN 的错误。
为了消除该错误,有三种方法可以选择: 1. 调大 tcp_sendspace,使之大于 send 中的 size 参数 ---no -p -o tcp_sendspace=65536
2. 在调用 send 前,在 setsockopt 函数中为 SNDBUF 设置更大的值
3. 使用 write 替代 send,因为 write 没有设置 O_NDELAY 或者 O_NONBLOCK
接收时
接收数据时常遇到 Resource temporarily unavailable 的提示,errno 代码为 11(EAGAIN)。这表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏 socket 的同步,不用管它,下次循环接着 recv 就可以。对非阻塞 socket 而言,EAGAIN 不是一种错误。在 VxWorks 和 Windows 上,EAGAIN 的名字叫做 EWOULDBLOCK。其实这算不上错误,只是一种异常而已。
另外,如果出现 EINTR 即 errno 为 4,错误描述 Interrupted system call,操作也应该继续。
最后,如果 recv 的返回值为 0,那表明对方已将连接断开,我们的接收操作也应该结束。