当前位置: 首页 > news >正文

使用socket函数的一些常见错误

1.socket

SOCKET socket( int af, int type, int protocol );

af(地址族):常为AF_INET 
使用AF_ISO等其他地址族标识,而非AF_INET。 
返回:-1。 
错误:10047(使用了与请求的协议不兼容的地址)

type(socket类型):通常为SOCK_STREAM或SOCK_DGRAM 
头文件中定义的只有如下几种标准类型: 
#define SOCK_STREAM 1 
#define SOCK_DGRAM 2 
#define SOCK_RAW 3 
#define SOCK_RDM 4 
#define SOCK_SEQPACKET 5 
使用非如上定义的类型。 
返回:-1。 
错误:10044(在这个地址家族中不存在对指定的插槽类型的支持)

protocol:通常为0

type = SOCK_STREAM,protocol = 6 
正常

type = SOCK_STREAM,protocol = 7 
返回:-1 
错误号:10043(请求的协议还没有在系统中配置,或者没有它存在的迹象)

type = SOCK_DGRAM,protocol = 17 
正常

type = SOCK_DGRAM,protocol = 19 
返回:-1 
错误号:10043(请求的协议还没有在系统中配置,或者没有它存在的迹象)

结论

  1. Socket暂时只支持AF_INET协议族。
  2. 对非标准的套接字类型不支持。
  3. 协议号参数可以为0,则使用与套接字类型相应的协议号;否则,协议号参数必须与相应的套接字类型相同。

2.bind

int bind( SOCKET s, const struct sockaddr FAR* name, int namelen );

s:在没有用socket申请资源的套接字上操作。 
返回:-1 
错误号:10038(在一个非套接字上尝试了一个操作)

name:通常使用AF_INET地址族、INADDR_ANY(0)地址

  1. 在local结构中,sin_family成员赋值为AF_OSI, 
    返回: -1 
    错误码:10047(使用了与请求的协议不兼容的地址)
  2. 在local结构中,sin_addr成员赋值为本计算机的IP地址,
  3. 在local结构中,sin_addr成员赋值为非本计算机的IP地址,如同小组的另一个同学的IP地址; 
    返回: -1 
    错误码:10049( 在其上下文中,该请求的地址无效)
  4. 在local结构中,sin_port成员赋值为135; 
    返回: -1 
    错误码:10048(通常每个套接字地址(协议/网络地址/端口)只允许使用一次)

namelen:通常为name所指的结构的大小,如sizeof(SOCKADDR_IN)

  1. namelen = 10 
    返回: -1 
    错误码:10014(系统检测到在一个调用中尝试使用指针参数时的无效指针地址)
  2. namelen = 16 
    返回: 0 
    正常
  3. namelen = 40 
    返回: 0 
    正常

结论

  1. 可以bind本机拥有的地址(或INADDR_ANY),非本机拥有的地址出错。
  2. bind已经被占用的端口值会出错。
  3. len参数要大于等于地址结构实际上所占的长度。

思考

  1. 因为本机可以有多个IP,所以需要有方法指出从哪个实体接收数据。
  2. 当然,提供一种表达“从所有实体接收”的方法是必要的。
  3. 在头文件中INADDR_ANY被明确定义为0。
  4. 关于bind已占用的端口。是指端口被bind,并且上层还是活的。(不设置复用)处于TIME-WAIT状态的端口表面上是被占用,实际上是可以bind成功的,但connect会失败。详见关于TIME-WAIT的笔记,第六条。

3.listen

int listen(SOCKET s, int backlog);


使用尚未半相关的套接字。(未成功bind的) 
返回:-1 
错误号:10022(提供了一个无效的参数)

backlog 
纯引用一段:(无出处)

“windows套接字实现中最多只允许服务器同时监听5个套接字。使用参数0,则系统将把该参数改为1,而使用超过5的值,系统将自动把该参数改为5。”

  设置参数值为0,有1个客户机可同时与服务器连接(在vista下有时有2个可以连接,有时有3个可以连接,-_0//)设置参数值为1,有1个客户机可同时与服务器连接设置参数值为10,有10个客户机可同时与服务器连接

结论

  1. 第一个参数的套接字必须是成功bind过后的。
  2. 监听个数为0的话,会自动设置为1。
  3. 最大监听个数在XP SP3下可以超过5。

问题

  1. 如何获得实际的backlog值? 
    MSDN: There is no standard provision to obtain the actual backlog value.

  2. 如何结束套接字的监听状态? 
    首先,close掉是可以的。如果不close呢?最初猜想backlog为0,-1等特殊值可以达到此效果,结果失败。求解。

4.accept

SOCKET accept( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen );


在没有listen的套接字上面。 
返回:-1 
错误号:10022(提供了一个无效的参数)

addr,输出参数,一般不填 

单机测试,填上本机的IP和某个端口号。 
结果:无法限制所接收的地址,执行完后addr中存放实际的地址。

addrlen 
同bind

结论

  1. 主套接字必须处于监听状态。
  2. 在地址字段填上任何值不能限制接受的连接。
  3. len参数要求所携带的值大于等于16。(AF_INET地址结构的长度)

5.recv

int recv( SOCKET s, char FAR* buf, int len, int flags ); 

对于服务器,一般是ns = accept(s , &addr , &len) ;

s,一般是用上面accept正常返回的值

  1. 在没有accept的从套接字上操作。(上面的ns) 
    返回:-1 
    错误号:10038(在一个非套接字上尝试了一个操作)

  2. 在主套接字上操作。(上面的s) 
    返回:-1 
    错误号:10057(由于套接字没有连接并且 
    (当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。 )

buf,要求指向一个有效的缓冲区 
如果指向的无效的内存区域 
返回: -1 
错误号:10014(系统检测到在一个调用中尝试使用指针参数时的无效指针地址)

len,发送的字节数 
len过长可能造成缓冲区溢出。 
这个属于编程中的普遍考虑问题,不是socket函数特有。

flags,一般用0 
设置MSG_PEEK标志后,接收但不移除数据。 (再次接收可得到相同的数据)

结论

  1. 对服务器来说,必须传递成功accept之后返回的套接字
  2. 缓冲区指针所指位置必须有效。
  3. 缓冲区长度参数不可超过实际准备的缓冲区长度。
  4. MSG_PEEK标志在接收的时候将保留数据。

6.send

int send( SOCKET s, const char FAR* buf, int len, int flags );

s,同recv

  1. 在没有accept的从套接字上操作。(上面的ns) 
    返回:-1 
    错误号:10038(在一个非套接字上尝试了一个操作)

  2. 在主套接字上操作。(上面的s) 
    返回:-1 
    错误号:10057(由于套接字没有连接并且 
    (当使用一个 sendto 调用发送数据报套接字时)没有提供地址, 
    发送或接收数据的请求没有被接受。 )

buf 
必须指向有效缓冲区,同recv

len 
必须和要发送的数据长度一致。

结论 
除flag可选项不同外,和recv一致。

7.closesocket

int closesocket( SOCKET s );

s

  1. 在申请套接字资源(调用socket)之前closesocket 
    返回: -1 
    错误号:10038(在一个非套接字上尝试了一个操作)

  2. 再已经closesocket的套接字上closesocket 
    返回: -1 
    错误号:10038(在一个非套接字上尝试了一个操作)

结论 

s必须是有效打开的套接字。 
不得重复关闭。

8.connect

int connect( SOCKET s, const struct sockaddr FAR* name, int namelen );

没有对端响应的情况 
在没有运行服务器的情况下,connect是否会一直阻塞? 
结果:等待一定时间后返回错误。 
返回: -1 
错误码:10061(由于目标机器积极拒绝,无法连接)


没有使用过bind的套接字。 
成功连接。 
产生隐式绑定,相关应用的详细资料。

name 
使用一些特殊的地址来测试。

  1. 使用远端点IP地址为INADDR_ANY测试。 
    返回:-1 
    错误号:10049(在其上下文中,该请求的地址无效)

  2. 使用远端点IP地址为10.1.1.255广播地址。 
    返回: -1 
    错误号:10060(由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败)

namelen 
同bind等需要传递地址结构长度的函数

结论

  1. 服务器必须启动listen。
  2. 可以不建立本地半相关,则进行隐式绑定。
  3. 客户不可以与INADDR_ANY主动相连,立即返回报错。
  4. 客户不可以与广播地址连接,会等待很久,返回失败。

讨论 

10060和10061两种错误不同。 
其中10061解释为目标机器积极拒绝,返回错误很快(秒级)。 
10060的情况,返回错误需要很长时间(几十秒级)。 
此处值得深入研究,两种情况下的抓包应该不一样。

9.recvfrom

int recvfrom( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR* from, int FAR* fromlen );

缺少半相关 
在没有bind的套接字上面,直接recvfrom。 
返回:-1 
错误号:10022(提供了一个无效的参数)

填写from结构 
向其中填入非对端使用的地址或端口。 
正常接收,并且from内置对端地址信息。

结论 

必须先进行本地半相关,指定端口,才能够接收。 
无法通过recvfrom的地址结构限制接收的地址和端口。

10.sendto

int sendto( SOCKET s, const char FAR* buf, int len, int flags, const struct sockaddr FAR* to, int tolen );

缺少半相关 
在没有bind的套接字上面,直接sendto。 
成功。返回发送的数据个数。

不存在的对端实体

  1. sendto到一个不存在的实体(to结构) 
    返回:发送的字符数 
    错误号:无

  2. 紧接着调用recvfrom 
    结果:没有阻塞,直接返回 
    返回:-1 
    错误号:10054 (远程主机强迫关闭了一个现有的连接。)

结论

  1. 可以在未本地半相关的情况下发送数据。由系统随机选择端口。

  2. 可以向不存在的远端点发送数据,本地仍然报告发送的字节数(不管有没有人接收)。

  3. 一般情况下,没有数据的时候recvfrom会阻塞。但是当给不存在的对端发送过数据后,会收到错误报告,紧接着的一次recvfrom会立即返回失败。(后面的仍然阻塞)

思考

  1. SOCK_DGRAM类型的服务,无法为用户确保数据的正常交付。但是通过recvfrom返回的错误,可以对发送情况作出一定的判断。

  2. 这也启示在使用SOCK_DGRAM时候的编程框架要考虑下,当recvfrom错误的时候,判断一下错误号,再进一步处理。

相关文章:

  • 数据链路层协议(Ethernet、IEEE802.3、PPP、HDLC)
  • IP协议详解
  • TCP协议
  • 浅谈 Excel 对象模型
  • WINMM
  • ACM-音频编解码器管理器
  • WDM驱动
  • Node.js详解-1
  • Node.js详解-2
  • Node.js详解-3
  • Node.js详解-4
  • wxWidgets
  • Qt开发简介-1
  • Qt开发简介-2
  • 深入理解信号槽机制
  • Angular 2 DI - IoC DI - 1
  • angular2 简述
  • ECMAScript入门(七)--Module语法
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • JS笔记四:作用域、变量(函数)提升
  • Linux链接文件
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 力扣(LeetCode)22
  • 浅谈Golang中select的用法
  • 区块链技术特点之去中心化特性
  • 实现简单的正则表达式引擎
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 【云吞铺子】性能抖动剖析(二)
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • !!Dom4j 学习笔记
  • #1015 : KMP算法
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (11)MATLAB PCA+SVM 人脸识别
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (分布式缓存)Redis分片集群
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (六)Hibernate的二级缓存
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转)编辑寄语:因为爱心,所以美丽
  • .NET CLR Hosting 简介
  • .net framework4与其client profile版本的区别
  • .NET Framework杂记
  • .NET gRPC 和RESTful简单对比
  • .NET 反射的使用
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • [ IOS ] iOS-控制器View的创建和生命周期
  • [BJDCTF2020]The mystery of ip1
  • [BZOJ2281][SDOI2011]黑白棋(K-Nim博弈)
  • [C++核心编程](四):类和对象——封装
  • [DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]
  • [Eclipse] 详细设置护眼背景色和字体颜色并导出
  • [flask]http请求//获取请求体数据
  • [LaTex]arXiv投稿攻略——jpg/png转pdf