c语言 socket 非阻塞,C语言Socket入门非阻塞socket(connect timieout问题)

c语言 socket 非阻塞,C语言Socket入门非阻塞socket(connect timieout问题)如果客户端想连接一个服务器端 但是不能肯定服务器端是否存在 如果存在了是否能连上 怎么判断呢 connect 函数的默认行为是阻塞的 会一直等待在那里 为了判断各种情况 以及遇到错误时结束连接 我们需要使用非阻塞的 socket 一个例子程序 include include include include include include include includeintma void i

如果客户端想连接一个服务器端,但是不能肯定服务器端是否存在,如果存在了是否能连上,怎么判断呢?

connect函数的默认行为是阻塞的,会一直等待在那里。为了判断各种情况,以及遇到错误时结束连接,我们需要使用非阻塞的socket。一个例子程序:

#include

#include

#include

#include

#include

#include

#include

#include

int main(void){

int s,r,ret,len,error;

char buf[20];

struct sockaddr_in sock;

fd_set rset,wset;

struct timeval tv;

tv.tv_sec=10;

s=socket(AF_INET,SOCK_STREAM,0);

if(-1==s){ printf(“socket() failed/n”); return 1;

}

if(0>fcntl(s,F_SETFL,fcntl(s,F_GETFL,0)|O_NONBLOCK)){

printf(“fcntl failed/n”);

return 1; }

sock.sin_family=PF_INET;

sock.sin_port =htons(10080);

sock.sin_addr.s_addr=inet_addr(“197.0.0.9”);

if(-1==(ret=connect(s,(struct

sockaddr*)&sock,sizeof(struct

sockaddr_in)))){

if(EINPROGRESS!=errno){

printf(“connect()

failed:%s/n”,strerror(errno)); return 1; }

}

if(ret==0){ printf(“connection ok at once/n”);

close(s); return 0; }

FD_ZERO(&rset);

FD_SET(s,&rset);

wset=rset;

if(-1==(ret=select(s+1,&rset,&wset,NULL,&tv))){

close(s);

printf(“select

error/n”);

return 1; }

if(0==ret){ close(s); printf(“timeout/n”); return

1; }

if(FD_ISSET(s,&rset)||FD_ISSET(s,&rset)){

len=sizeof(error);

errno=0;

if(0>(ret=getsockopt(s,SOL_SOCKET,SO_ERROR,(void*)&error,&len))){

printf(“getsockopt

error:%s/n”,strerror(error));

close(s);

return 1;

}

if(error!=0){ printf(“getsockopt set

error:%s/n”,strerror(error)); close(s); return 1;

}

printf(“getsockopt success/n”);

}else{ close(s); printf(“FD_ISSET error/n”);

return 1; }

if(-1==(ret=read(s,buf,sizeof(buf)))){

printf(“read() failed/n”); return 1; }

printf(“ret=%d/n”,ret);

buf[ret-1]=’/0′;

printf(“read:%s/n”,buf);

close(s);

return 0;

}

解释:

1. socket()得到的句柄使用fcntl函数设置了非阻塞的特性。

程序中的ip地址197.0.0.9并不存在,connect失败,select会等待(10秒),一直到timeval超时结束。

2.

如果把ip地址改为一个存在的地址,例如127.0.0,1这样,那么connect函数返回的错误值就是ECONNREFUSED。并且这种情况下select函数会立刻返回,getsockopt函数设置&error,这个可以被strerror()函数打印。—-tcp协议是这么规定的。如果连接一个存在的ip,但是这个ip的机器没有监听你要连接的端口,它会返回rst报文。(当然首先是那个ip的机器支持tcp/ip协议,不过这点现在机器都支持)如果发生连接错误,

也会让socket可读和可写.

服务器没有启动, 所以肯定会发生连接错误,这时,

连接已可读可写, select没有必要等待超时.

3. connect函数失败以后,socket句柄的状态是未定义的,应该close(s)再生成一个。

select的作用是检查描述符的状态,是否有数据过来,比如

要查读描述符,那就检查读描述符的状态,有数据来,就会返回,否则,一直等待,知道你设定的超时时间退出。

而你上面的connect的问题,不是这个。

对于tcp/ip,每个机器只要支持tcp/ip协议,那么它一启动,就相当于有个负责tcp/ip的进程在后台运行着。再说connect,connect的过程

就是 发包收包的过程,用抓包工具可以看到。

connect的过程是:比如a去连b,以下是正常连接的情况。

a:首先发送一个数据包给b

b:收到a的包后给a回一个包。

a:收到b回的包后再给b回一个包。

这三次完成后,就是connect成功连接上,返回了。

上面的程序改为连一个存在的ip(127.0.0.1),但是对方没有在你要连得端口监听会像下面这样:

a:发一个包给b

b:发现没有监听,回rst给a

然后connect没连上结束了。

4. 其他的分析:

最初的地址如果用 INADDR_ANY,会报地址错误。

如果用合法地址,对方没有侦听,报连接被拒绝。Connection refused

如果对方在听了,但没有向你发送消息,select 认为文件描述符是不可读的。

如果三路握手完成,则 select 认为文件描述符是可写的。

写一个服务去听,客户在 select 时把 *wset 参数 设

NULL 就可以观察到 timeout。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/228875.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午5:59
下一篇 2026年3月16日 下午5:59


相关推荐

  • nmap命令详解「建议收藏」

    nmap命令详解「建议收藏」nmap是一个网络探测和安全扫描程序,系统管理者和个人可以使用这个软件扫描大型的网络,获取那台主机正在运行以及提供什么服务等信息。nmap支持很多扫描技术,例如:UDP、TCPconnect()、TCPSYN(半开扫描)、ftp代理(bounce攻击)、反向标志、ICMP、FIN、ACK扫描、圣诞树(XmasTree)、SYN扫描和null扫描。从扫描类型一节可以得到细节。nmap还

    2022年5月8日
    152
  • iloc函数使用方法

    iloc函数使用方法iloc 前面的冒号就是取行数 后面的冒号是取列数找了一个例子做实践 importnumpya pyplotasplti pd read csv Position Salaries csv dataset head 5 X dataset iloc 1 2 values 第 2 列 1 level 左闭右开 y datase

    2026年3月26日
    2
  • 经典C面试题

    经典C面试题

    2021年11月30日
    40
  • 修改MySQL端口_windows安装mysql数据库

    修改MySQL端口_windows安装mysql数据库我的MySQL是解压免安装版的,要修改MySQL的端口,方法很简单:解压MySQL后,在MySQL根目录下有一个my-default.ini,打开它,上面的注释写的很清楚“#***DONOTEDITTHISFILE…..”将该文件复制粘贴一份,重命名为:my.ini,还是放在根目录下然后,里面有个#port=……去掉注释,并修改为你想要的端口,如port=3337…

    2022年10月3日
    5
  • matlab中ode45函数解二阶微分方程_matlab求常微分方程组

    matlab中ode45函数解二阶微分方程_matlab求常微分方程组Matlab微分方程求解并绘制曲线1.用dsolve()求解>>clear>>clc>>symsy(t)>>Dy=diff(y,1)Dy(t)=diff(y(t),t)>>y=dsolve(Dy==y-2*t/y,y(0)==1)y=(2*t+1)^(1/2)>>t=0:0.1:4;>>y=eval(y);>>plot(t,

    2025年8月9日
    4
  • ubuntu 硬盘安装图解

    ubuntu 硬盘安装图解br MaverickMeer 10 启用了全新的安装程序 使得整个安装过程不但焕然一新 对那些不太熟悉 Linux 环境的用户来说也更容易使用了 br 在安装过程中 用户可以下载软件更新 安装无线网卡官方驱动 并完成对 MP3 音频文件 AdobeFlashPl 播放器 Java DVD 播放的支持 br 下面说说在 WindowsXP 系统下硬盘安装 Ubuntu10 10 双系统的全程图解 安装很快 30 分钟不到就能安装好 br 1 首先下

    2025年11月8日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号