在编写ftp客户端程序时,在联通后使用recv函数进行接收欢迎信息时,需要申请内存进行接收数据保存,一次读取成功,但是由于一个随机的ftp服务端在说,欢迎信息的大小是不知道的,所以在尝试使用死循环,在阅读recv的说明时讲到返回值即是接收到的字节数,那么返回0的时候就代表结束了,实践发现recv是个阻塞函数,在连接不断开的情况下,会一直处于阻塞状态,也不会返回0.也就是说程序不能这么一直读,如果对端连接没有关闭,则在没有数据的情况下,调用recv会阻塞,如果对端关闭连接,则立即返回0.

所以就需要使用到select函数来操作。

MSDN中对select的介绍连接为:ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/winsock/winsock/select_2.htm

select的功能为检测一个或者多个socket是否可读或者可写,或者有错误产生。根据设置可以处于阻塞、非阻塞、等待固定时间返回。

原型:

select Function

The select function determines the status of one or more sockets, waiting if necessary, to perform synchronous I/O.

int select(
__in int nfds,
__in_out fd_set* readfds,
__in_out fd_set* writefds,
__in_out fd_set* exceptfds,
__in const struct timeval* timeout
);
 

Parameters

nfds

Ignored. The nfds parameter is included only for compatibility with Berkeley sockets.

忽略。nfds参数在这里只是为了和伯克利套接字相兼容。(这个参数在linux中有意义)

readfds

Optional pointer to a set of sockets to be checked for readability.

指向一组等待判断可读性的socket的指针,可不设置。

writefds

Optional pointer to a set of sockets to be checked for writability.

指向一组等待判断可写性的socket的指针,可不设置。

exceptfds

Optional pointer to a set of sockets to be checked for errors.

和上面两个一样,指向待检测是否发生错误的一组socket的指针,可不设置。

timeout

Maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to null for blocking operations.

select函数最大等待时间,使用TIMEVAL结构体。设置为NULL时阻塞。

TIMEVAL结构体定义如下:

typedef struct timeval {
long tv_sec; //秒
long tv_usec; //毫秒
} timeval;

Return Value

        返回fd_set结构中准备好的(可读、可写或者发生错误)socket句柄的总个数。等待时间到则返回0,发生错误返回SOCKET_ERROR。
 
 
操作fs_set结构

windows提供几个宏对fs_set结构进行操作:

FD_CLR(s, *set)

Removes the descriptor s from set.

从fd_set集合中移除一个描述符。

FD_ISSET(s, *set)

Nonzero if s is a member of the set. Otherwise, zero.

检测一个描述符是否是fd_set集合的可读或者可写成员,不在返回0,是返回非0.

FD_SET(s, *set)

Adds descriptor s to set.

向fs_set集合中添加一个描述符。

FD_ZERO(*set)

Initializes the set to the null set.

初始化fd_set集合为NULL。

例子:

以读取FTP服务器的欢迎信息为例。

注意:在使用过程中如果只是想检测可读,千万不要在写检测的参数里同时赋值。我在写例子的过程中不小心将同一个rfds同时赋在了读写参数里,结果是虽然不可读了,但是select仍然返回非0值,因为同一个socket可写。找了半天才发现错误。

这样就不用担心申请的内存空间不能一次读完缓冲区了。也不用担心recv一直阻塞在那里了。

#include<stdio.h>
#include <winsock2.h>
#include <string.h> int main(void)
{
SOCKET fp;
FILE * ffp;
struct fd_set rfds;
struct sockaddr_in ipadd;
struct timeval timeout = {,};
char * readbuff[] = {};
WSADATA wData; WSAStartup(0x0202,&wData);
fp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); memset(&ipadd, , sizeof(struct sockaddr_in));
ipadd.sin_family = AF_INET;
ipadd.sin_addr.s_addr = inet_addr("192.168.1.101");
ipadd.sin_port = htons(); if( != connect(fp, &ipadd, sizeof(struct sockaddr_in)))
{
printf("\r\nerror");
}
ffp = fopen("test.txt", "rw+");
int ret;
while()
{
FD_ZERO(&rfds); /* 清空集合 */
FD_SET(fp, &rfds); /* 将fp添加到集合,后面的FD_ISSET和FD_SET没有必然关系,这里是添加检测 */ ret=select(, &rfds, NULL, NULL, &timeout);
printf("\r\nselect ret = %d",ret);
if( > ret)
{
closesocket(fp);
fclose(ffp);
return -;
}
else if( == ret)
{
break;
}
else
{
if(FD_ISSET(fp,&rfds)) /* 这里检测的是fp在集合中是否状态变化,即可以操作。 */
{
ret = recv(fp, readbuff, , );
<span style="white-space:pre"> </span>if( == ret) return ; /* 此处需要检测!否则ftp发送数据时,后面会循环接收到0字节数据 */
// printf("\r\n%s",readbuff);
fputs(readbuff, ffp);
memset (readbuff,,);
}
} }
printf("\r\nread successful!");
fclose(ffp);
closesocket(fp);
}

见  http://blog.csdn.net/kikilizhm/article/details/8201512

【转】【win网络编程】socket中的recv阻塞和select的用法的更多相关文章

  1. 网络编程socket基本API详解(转)

    网络编程socket基本API详解   socket socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信. socket ...

  2. 铁乐学Python_Day33_网络编程Socket模块1

    铁乐学Python_Day33_网络编程Socket模块1 部份内容摘自授课老师的博客http://www.cnblogs.com/Eva-J/ 理解socket Socket是应用层与TCP/IP协 ...

  3. Python网络编程socket

    网络编程之socket 看到本篇文章的题目是不是很疑惑,what is this?,不要着急,但是记住一说网络编程,你就想socket,socket是实现网络编程的工具,那么什么是socket,什么是 ...

  4. java网络编程socket\server\TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅     1 TCP的开销 a ...

  5. Android 网络编程 Socket

    1.服务端开发 创建一个Java程序 public class MyServer { // 定义保存所有的Socket,与客户端建立连接得到一个Socket public static List< ...

  6. Linux网络编程-----Socket地址API

    (1) 通用socket地址 socket网络编程接口中表示socket地址的是结构体sockaddr,其定义如下: #include<bits/socket.h> struct sock ...

  7. 网络编程Socket之TCP之close/shutdown具体解释(续)

    接着上一篇网络编程Socket之TCP之close/shutdown具体解释 如今我们看看对于不同情况的close的返回情况和可能遇到的一些问题: 1.默认操作的close 说明:我们已经知道writ ...

  8. 第84节:Java中的网络编程(中)

    第84节:Java中的网络编程(中) 实现客户端和服务端的通信: 客户端需要的操作,创建socket,明确地址和端口,进行键盘录入,获取需要的数据,然后将录入的数据发送给服务端,为socket输出流, ...

  9. linux网络编程-socket(37)

    在编程的时候需要加上对应pthread开头的头文件,gcc编译的时候需要加了-lpthread选项 第三个参数是线程的入口参数,函数的参数是void*,返回值是void*,第四个参数传递给线程函数的参 ...

随机推荐

  1. EIGRP-6-EIGRP数据包

    EIGRP在与邻居路由器进行通信时,使用以下7种不同类型的数据包:   Hello包 确认包 更新包 查询包 响应包 SIA查询包 SIA响应包   更新包,查询包,响应包,SIA查询包和SIA响应包 ...

  2. LeetCode初级算法(动态规划+设计问题篇)

    目录 爬楼梯 买卖股票的最佳时机 最大子序和 打家劫舍 动态规划小结 Shuffle an Array 最小栈 爬楼梯 第一想法自然是递归,而且爬楼梯很明显是一个斐波拉切数列,所以就有了以下代码: c ...

  3. windows srver 显示桌面图标。

    rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0

  4. java基础---GC

    一.Java基础: GC即:garbage collection垃圾回收机制.Java是自动回收垃圾的,像c c++等语言没有自动垃圾回收机制,长时间开启服务器就会导致 内存泄漏,占用内存 Java的 ...

  5. python排序(冒泡、直接选择、直接插入等)

    冒泡排序 冒泡法:第一趟:相邻的两数相比,大的往下沉.最后一个元素是最大的. 第二趟:相邻的两数相比,大的往下沉.最后一个元素不用比. #冒泡排序 array = [1,5,6,2,9,4,3] de ...

  6. python3+Appium自动化05-xpath定位

    概念 xpath定位是一种路径定位方式,主要是依赖于元素绝对路径或者相关属性来定位,但是绝对路径xpath执行效率比较低(特别是元素路径比较深的时候),一般使用比较少.通常使用xpath相对路径和属性 ...

  7. Storm概念学习系列 之Worker工作者进程

    不多说,直接上干货! Worker工作者进程   工作者进程(Worker)是一个java进程,执行拓扑的一部分任务.一个Worker进程执行一个Topology的子集,它会启动一个或多个Execut ...

  8. Storm概念学习系列之storm的特性

    不多说,直接上干货! storm的特性 Storm 是一个开源的分布式实时计算系统,可以简单.可靠地处理大量的数据流. Storm支持水平扩展,具有高容错性,保证每个消息都会得到处理,而且处理速度很快 ...

  9. 提升Java代码质量(三)

    Item7:覆盖equals时需要遵守通用约定 在我们日常开发过程中,重写equals是比较常用的,但存在许多不合适的覆盖方式导致错误,最好的避免方法就是不去重写equals.但有时我们的业务又需要建 ...

  10. 从零开始的全栈工程师——js篇2.7(JS数据类型具体分析)

    JS数据类型具体分析与数据的三大存储格式 1. 字符串 string2. 数字 number3. 布尔 boolean4. null 空5. undefined 未定义↑↑↑叫基本数据类型 基本数据类 ...