网卡 filerecv的中文意思 trans 什么意思

君,已阅读到文档的结尾了呢~~
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
netperf测试网卡性能
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口linux回环网卡驱动设计
来源:博客园
回环网卡驱动
1.回环网卡和普通网卡的区别是他是虚拟的不是实际的物理网卡,它相当于把普通网卡的发送端和接收端短接在一起。
2.在内核源代码里的回环网卡程序(drivers/net/loopback.c)不是以一个模块的形式给出,但是他的初始化(loopback_net_init)和退出函数(loopback_dev_free)会被内核的其他部分调用到。
3.参照网卡初始化的流程图进行设计驱动程序,其中分配net_device结构不能用alloc_etherdev函数,因为该函数是分配以太网卡的结构体的,要用alloc_netdev函数来给回环网卡分配结构体。参考内核源代码别人如何用使用这个函数alloc_netdev(0, "lo", loopback_setup);第一个0表示net_device这个结构体的私有成员的大小,一般选择0,第二个表示网卡名字,ifconfig显示的名称,第三个就是具体的网卡结构体的初始化函数指针。
struct net_device *
dev = alloc_netdev(0, "lo", loopback_setup);
最终会调用到loopback_setup函数。(至于在将函数指针作为参数的时候如何传递形参,就要复习C语言了)
4.回环网卡不需要初始化硬件。所以直接注册回环网卡的结构体到内核(第三步)。最后指定回环网卡注册到网络子系统。
net-&loopback_dev =这一步很关键。
5.具体的初始化(loopback_setup)(第二步)
(1)基地址,MAC地址以及中断号都用不着,主要是netdev_ops这个结构体,他包含了这个网卡支持的操作。
(2)表示回环网卡支持的最大的接收数据的包的大小,除了正式数据,还有相关网络协议的头部分。
dev-&mtu
= (16 * 1024) + 20 + 20 + 12;有效数据一般定义为16KB。
(3)加上表示回环网卡专有的标志。
dev-&flags
= IFF_LOOPBACK;
、
(4)加上构造报头的结构体指针,这个结构体指针指向的结构体成员是众多构造以太网报头的函数指针。
dev-&header_ops
= &eth_header_
理想查找可看到
extern const struct header_ops eth_header_
struct header_ops {
(*create) (struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr,
const void *saddr, unsigned len);
(*parse)(const struct sk_buff *skb, unsigned char *haddr);
(*rebuild)(struct sk_buff *skb);
#define HAVE_HEADER_CACHE
(*cache)(const struct neighbour *neigh, struct hh_cache *hh);
(*cache_update)(struct hh_cache *hh,
const struct net_device *dev,
const unsigned char *haddr);
};
6.数据发送
static int loopback_net_xmit(struct sk_buff *skb,struct net_device *dev){ skb-&protocol = eth_type_trans(skb,dev);
 packets++; bytes += skb-&
 netif_rx(skb); return 0;}

}
(1)第一个参数是协议栈传送给回环网卡的包数据,第二个参数是回环网卡的结构体。
(2)停止发送队列
通知上层暂停送数据,好让txd发送已送达的数据,但是不涉及硬件,所以在回环网卡可忽略。相应的,将数据写入寄存器和唤醒再次发送以及释放队列就可忽略。
(3)信息统计,表明上层送下来的包的协议
skb-&protocol = eth_type_trans(skb, dev);
(4)统计发送过来的数据大小以及包的个数。
bytes += skb-&
netif_rx(skb);

7.由于从协议栈来的数据包(skb)存放到txd,而且txd不需要往外发送,txd和rxd“连”在一起,所以直接在发送部分调用普通网卡的接收部分的netif_rx(skb)函数,所以发送的同时就完成了接收。同时我们更清楚地看到在发送的时候不能释放skb,否则没有可接收的数据。
8.实现获取网卡状态的函数
static struct net_device_stats *loopback_get_stats(struct net_device *dev){ struct net_device_stats *stats = &dev-&
 stats-&rx_packets = stats-&tx_packets = stats-&rx_bytes = stats-&tx_bytes = }

从这个结构体可以获取网卡状态信息
/* The main device statistics structure */
struct rtnl_link_stats64 {
/* total packets received
/* total packets transmitted
/* total bytes received
/* total bytes transmitted
/* bad packets received
/* packet transmit problems
/* no space in linux buffers
/* no space available in linux
/* multicast packets received
__u64
/* detailed rx_errors: */
rx_length_
/* receiver ring buff overflow
/* recved pkt with crc error
/* recv'd frame alignment error */
/* recv'r fifo overrun
rx_missed_
/* receiver missed packet
/* detailed tx_errors */
tx_aborted_
tx_carrier_
tx_fifo_
tx_heartbeat_
tx_window_
/* for cslip etc */
tx_
};
主要是这四个成员
  stats-&rx_packets =
stats-&tx_packets =
stats-&rx_bytes
stats-&tx_bytes
=
。实际上自己可以重写这个获取状态的函数,因为struct net_device *dev有一个成员就是struct net_device_所以可以在重写的时候定义一个struct net_device_stats
stats指向形参传递进来的回环网卡结构体的stats成员,同样只需要注意stats成员的上述四个成员即可。
9.在退出该驱动的时候就是取消注册结构体。达到注销网卡的目的。
static __net_exit void loopback_net_exit(struct net *net){ struct net_device *dev = net-&loopback_
 unregister_netdev(dev);}
 
 
下面为范例代码

#include &linux/kernel.h&
#include &linux/module.h&
#include &linux/types.h&
#include &linux/errno.h&
#include &linux/init.h&
#include &linux/netdevice.h&
#include &linux/etherdevice.h&
#include &linux/skbuff.h&
#include &linux/if_ether.h&
/* For the statistics structure. */


unsigned long bytes = 0;
unsigned long packets = 0;


static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{

skb-&protocol = eth_type_trans(skb,dev);
//标明数据包的协议---以太网协议


bytes += skb-&
//发送包的长度
packets++;
//包的数目

netif_rx(skb);

return 0;
}

static struct net_device_stats *loopback_get_stats(struct net_device *dev)
{
struct net_device_stats *stats = &dev-&
stats-&rx_packets =
stats-&tx_packets =
stats-&rx_bytes =
stats-&tx_bytes =
return
}

static const struct net_device_ops loopback_ops = {
.ndo_start_xmit= loopback_xmit,
.ndo_get_stats = loopback_get_stats,
//获取网卡状态信息
};

/*
 * The loopback device is special. There is only one instance
 * per network namespace.
 */
static void loopback_setup(struct net_device *dev)
{
= (16 * 1024) + 20 + 20 + 12; //网卡能接收的最大数据包的大小 tcp头 20 以太网头 20 ip头 12
dev-&flags
= IFF_LOOPBACK;
//回环网卡标志位
dev-&header_ops
= &eth_header_
//数据头的构造函数(以太网头构造函数) 直接使用内核自带的函数 内核自动调用该函数
dev-&netdev_ops
= &loopback_
//网卡操作函数集

}

/* Setup and register the loopback device. */
static __net_init int loopback_net_init(struct net *net)
{
struct net_device *
err = -ENOMEM;
dev = alloc_netdev(0, "lo", loopback_setup);
//分配net_device结构-alloc_etherdev(以太网)
setup初始化netdev
if (!dev)
goto out;

err = register_netdev(dev);
if (err)
goto out_free_

net-&loopback_dev =
//将分配好的dev告诉网络(回环网卡特有)
return 0;


out_free_netdev:
free_netdev(dev);
out:
if (net == &init_net)
panic("loopback: Failed to register netdevice: %d\n", err);
return
}

static __net_exit void loopback_net_exit(struct net *net)
{
struct net_device *dev = net-&loopback_

unregister_netdev(dev);
}

/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops = {
.init = loopback_net_init,
.exit = loopback_net_exit,
};

免责声明:本站部分内容、图片、文字、视频等来自于互联网,仅供大家学习与交流。相关内容如涉嫌侵犯您的知识产权或其他合法权益,请向本站发送有效通知,我们会及时处理。反馈邮箱&&&&。
学生服务号
在线咨询,奖学金返现,名师点评,等你来互动博客访问: 27183
博文数量: 6
博客积分: 1612
博客等级: 上尉
技术积分: 80
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
NAPI驱动流程:
& & 中断发生
& & --&确定中断原因是数据接收完毕(中断原因也可能是发送完毕,DMA完毕,甚至是中断通道上的其他设备中断)
& & --&通过netif_rx_schedule将驱动自己的napi结构加入softnet_data的poll_list链表,禁用网卡中断,并发出软中断
--&中断返回时触发软中断net_rx_action,从softnet_data的poll_list上取下刚挂入的napi结构,并且调用其
poll函数,这个poll函数也是驱动自己提供的,比如rtl8139网卡驱动中的rtl8139_poll等。
& & --&在poll函数中进行轮询,直到接受完所有的数据或者预算(budget)耗尽。每接收一个报文要分配skb,用eth_type_trans处理并交给netif_receive_skb。
& & --&如果数据全部接收完(预算没有用完),则重新使能中断并将napi从链表中取下。如果数据没接收完,则什么也不作,等待下一次poll函数被调度。
非NAPI流程:
& & 中断发生
& & --&确定中断发生的原因是接收完毕。分配skb,读入数据,用eth_type_trans处理并且将skb交给netif_rx
--&在netif_rx中,将packet加入到softnet_data的input_pkt_queue末尾(NAPI驱动不使用这个
input_pkt_queue),再通过napi_schedule将softnet_data中的backlog(这也是个napi结构)加入
softnet_data的poll_list,最后发出软中断
& & --&软中断net_rx_action从poll_list上取下softnet_data的backlog,调用其poll函数,这个poll函数是内核提供的process_backlog
& & --&函数process_backlog从softnet_data的input_pkt_queue末尾取下skb,并且直接交给netif_receive_skb处理。
& & --&如果input_pkt_queue中所有skb都处理完则将backlog从队列中除去(注意input_pkt_queue中可能有多个网卡加入的报文,因为它是每cpu公用的)并退出循环;如果预算用完后也跳出循环。最后返回接受到的包数
NAPI和非NAPI的区别
& & 1.NAPI使用中断+轮询的方式,中断产生之后暂时关闭中断然后轮询接收完所有的数据包,接着再开中断。而非NAPI采用纯粹中断的方式,一个中断接收一个数据包
& & 2.NAPI都有自己的struct napi结构,非NAPI没有
& & 3.NAPI有自己的poll函数,而且接收数据都是在软中断调用poll函数时做的,而非NAPI使用公共的process_backlog函数作为其poll函数,接收数据是在硬件中断中做的
4.NAPI在poll函数中接收完数据之后直接把skb发给netif_receive_skb,而非NAPI在硬件中断中接收了数据通过
netif_rx把skb挂到公共的input_pkt_queue上,最后由软中断调用的process_backlog函数来将其发送给
netif_receive_skb
驱动以及软中断这块对skb仅仅做了以下简单处理:
& & 1.调用skb_reserve预留出2个字节的空间,这是为了让ip首部对齐,因为以太网首部是14字节
& & 2.调用skb_put将tail指向数据末尾
& & 3.调用eth_type_trans进行如下处理:
& && &&&(1)将skb-&dev指向接收设备
& && &&&(2)将skb-&mac_header指向data(此时data就是指向mac起始地址)
& && &&&(3)调用skb_pull(skb, ETH_HLEN)将skb-&data后移14字节指向ip首部
& && &&&(4)通过比较目的mac地址判断包的类型,并将skb-&pkt_type赋值PACKET_BROADCAST或PACKET_MULTICAST或者PACKET_OTHERHOST,因为PACKET_HOST为0,所以是默认值
& && &&&(5)最后判断协议类型,并返回(大部分情况下直接返回eth首部的protocol字段的值),这个返回值被存在skb-&protocol字段中
总结,结束后,skb-&data指向ip首部,skb-&mac_header指向
mac首部,skb-&protocol储存L3的协议代码,skb-&pkt_type已被设置,skb-&len等于接收到的报文
长度减去eth首部长度,也就是整个ip报文的总长。其余字段基本上还是默认值。
netif_receive_skb
1.将skb-&iif赋值为skb-&dev-&ifindex,将skb-&network_header和
skb-&transport_header都指向skb-&data,也就是ip首部,然后skb-&mac_len=skb-&
network_header-skb-&mac_header,正常情况下应该等于ETH_HLEN吧
& & 2.向ptype_all中注册(通过dev_add_pack)的每一个packet_type调用一次deliver_skb,这里没有拷贝skb,只是先增加了一下skb-&users
& & 3.调用handle_bridge处理桥报文,如果该dev不是一个桥端口则直接返回
& & 4.调用handle_macvlan处理vlan
& & 5.对于每一个在ptype_base中注册的packet_type(也是用dev_add_pack),调用deliver_skb
& & 6.如果没有任何一个注册的packet_type接受skb则直接kfree_skb并且返回NET_RX_DROP。否则返回最后一个pkt_type-&func返回的值
总结,需要说一下dev_add_pack,这个函数根据传入的packet_type的type字
段决定加入哪个队列,如果是ETH_P_ALL就加入ptype_all,否则计算哈希值并加入ptype_base,通过这个函数注册的都是L3层的协
议,比如ip,arp,rarp,bootp等,其实还有packet协议族套接字的监听函数(除了ETH_P_ALL之外都加入ptype_base,
它们对应的接收函数是packet_rcv),这里对于ip来说,接受函数就是ip_rcv。
经过这个函数,又有几个字段发生变化:
network_header和transport_header都指向ip首部,mac_len为mac首部长度
& & 1.丢弃所有pkt_type为OTHER_HOST的包,注意对于将网卡设为混杂模式的监听进程来说,这个包已经在netif_receive_skb中给它们发送了一份拷贝
& & 2.检查skb是否被共享,如果被共享需要用skb_clone拷贝一份,因为后面要对skb的内容进行变更
3.常规检测:如果报文的长度小于ip首部最小长度,丢弃;如果ip协议字段不等于4丢弃;若ip首部长度字段小于5,丢弃;若ip首部长度小于ip首部
长度字段*4,丢弃;如果ip首部校验和出错,丢弃;如果skb-&len(此时len为整个ip报文长度)小于ip首部总长字段,丢弃;如果ip
首部总长字段小于ip首部长度字段,丢弃;
4.注意第三步中skb-&len是可以小于ip首部的总长字段的,因为根据代码注释,传输介质有可能在末尾添加了padding,在这种情况下,
会调用pskb_trim_rcsum将多余的结尾部分砍掉(通过把skb-&tail往前移),并且还要将检查和无效化
& & 5.此处调用NF_INET_PRE_ROUTING钩子函数
总结,ip_rcv主要进行的常规检查,唯一对skb进行操作的就是将结尾的填充字段砍掉。
ip_rcv_finish:
& & 1.首先,如果skb-&dst为空,说明还不确定这个ip报文的目的地是本机还是别的机器,这时通过ip_route_input来找到rtable并且赋给skb-&rtable
2.如果ip首部长度字段大于5则调用ip_rcv_options处理ip选项。该函数调用ip_options_compile将选项全部处理放在
skb的cb字段中,作为一个struct
ip_options(还要详细看ip_options_compile)。如果有源站路由选项则检查设备是否支持源站路由(软件支持,可配置),则调用
ip_options_rcv_srr(此函数也还需认真看)填写源站路由。
3.添加统计信息并调用dst_input,dst_input只是调用skb-&dst-&input函数,这个skb-&dst就
是前面用ip_route_input确定的,而根据dst类型的不同,这个input函数可能是ip_local_deliver或者
ip_forward,这里我们看ip_local_deliver。
总结,ip_rcv_finish改变了skb-&dst字段(如果本来
skb-&dst字段已经有值则不改变)和skb-&cb字段(在ip_rcv_options中将ip首部选项编译之后放入cb)。
ip_options_compile可以改变报文内容,比如填写路由记录选项,填写时间戳选项等
ip_local_deliver
1.如果ip首部offset或者MF不为0,则调用ip_defrag进行ip分片的重组,ip_defrag只在成功完全重组了一个报文之后才会返回
0,其他情况都是返回非0,如果返回非0就会从ip_local_deliver返回。ip_defrag也比较复杂,需要细看,总体来说就是将分片放在
一个哈希表中,开启定时器,来一个分片就与前面属于同一ip报文的分片合并(两个分片是否属于同一个ip报文是通过ip的id字段,源目的地址,L4协议
等多个参数确定的,可参考ip4_frag_match)
& & 2.钩子NF_INET_LOCAL_IN,并调用ip_local_deliver_finish
总结,从上两个函数可以看出NF_INET_PRE_ROUTING和
NF_INET_LOCAL_IN之间的区别,前者还没有经过路由处理,即skb-&dst一般还没有确定,而后者是已经确定了
skb-&dst且dst为本地地址,假如skb-&dst不是本地地址则会调用ip_forward,这就不会触发
NF_INET_LOCAL_IN了。另外NF_INET_PRE_ROUTING尚未对ip分片进行合并处理,而NF_INET_LOCAL_IN抓到
的数据包是已经合并成的ip报文了
ip_local_deliver_finish
& & 1.将skb-&data继续移动指向传输层首部,并且将skb-&transport_header也指向传输层首部,接下来开始处理
& & 2.首先从ip首部取得传输层协议号,然后用这个协议号调用raw_local_deliver将skb传给raw_v4_hashinfo哈希表中的原始套接字协议
3.再利用protocol值作为下标取得inet_protos全局数组中的注册协议(对于tcp,udp,icmp分别是
tcp_protocol,udp_protocol,icmp_protocol)。如果找到了对应的协议处理结构,就把skb交给该结构的
handler函数处理(对于tcp,udp,icmp分别是tcp_v4_rcv,udp_rcv,icmp_rcv)。如果没找到对应的处理结构,则
回发一个icmp协议不可达的目的不可达报文,并释放skb。
总结:这里又一次移动了skb-&data指针,将其指向传输层首部,同时设置了
transport_header也指向传输层首部。raw_v4_hashinfo和inet_protos都是一个256项的全局数组,以协议号为下
标保存了各个协议的处理结构。这两个数组就像是L4层的ptype_base,根据本层的协议号来决定处理函数
注意区别raw_v4_hashinfo和上面的ptype_all,前者是AF_INET的SOCK_RAW套接字注册的接收结构,而后者是
AF_PACKET套接字注册的接收结构,可见raw套接字是经过了ip层处理的而packet是在netif_receive_skb中接收的,尚未经
过任何处理,其中一个显著区别就是raw经过了ip_defrag而packet没有
对于udp来说,inet_protos中的结构是全局变量udp_protocol,它的handler函数是udp_rcv
udp_rcv所做的就是直接调用__udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP);
__udp4_lib_rcv
& & 此函数中会调用__udp4_lib_lookup_skb--&()__udp4_lib_lookup()来查找此udp包对应的socket,主要是查找源目的地址和端口号都符合的socket。
& & 如果查找到了对应的socket,则调用udp_queue_rcv_skb将skb放入udp的接收队列,然后返回0
& & 如果没有查找到对应的socket,要向源地址发送一个ICMP端口不可达消息
udp_queue_rcv_skb
& & 它经过__udp_queue_rcv_skb(sk,
skb)--&__udp_queue_rcv_skb--&skb_queue_tail一系列调用过程将skb加入socket的接收队
列sk-&sk_receive_queuek末尾。其中还要检测接收缓冲区是否已经满。
& & 接着调用sk-&sk_data_ready(sk, skb_len)通知socket有数据就绪,可以读了。一般情况下这个函数对应sock_def_readable,这个函数的功能就是唤醒在sk-&sk_sleep上睡眠的进程
& & 那么是谁在这里睡眠呢?在调用recvfrom系统调用接收报文的时候,会经过这样一个流程
& & sys_socketcall
& & --&sys_recvfrom
& & --&sock_recvmsg
& & --&__sock_recvmsg
& & --&sock-&ops-&recvmsg,这个sock-&ops对应全局变量inet_dgram_ops,里面的recvmsg对应sock_common_recvmsg
& & --&sock_common_recvmsg
& & --&sk-&sk_prot-&recvmsg,这个sk-&sk_prot对应全局变量udp_prot,里面的recvmsg对应udp_recvmsg
& & --&udp_recvmsg
& & --&__skb_recv_datagram
在__skb_recv_datagram中,会首先尝试从sk-&sk_receive_queue上取下数据包,如果发现队列中没有数据包,则
开始在sk-&sk_skeep上睡眠。而上面sock_def_readable唤醒的就是这里睡眠的进程。
可以看到,在__skb_recv_datagram中被唤醒后,函数又尝试从sk-&sk_receive_queue上取下数据包,这时当然会
成功,成功之后返回到udp_recvmsg。udp_recvmsg再进行一些简单的检测之后就调用copy_to_user将数据拷贝到用户空间了
(其实这里并不是简单调用copy_to_user,还要处理很多情况,比如用户使用的msghdr可能包含多个iovec,skb可能有多个frags
这样,一个udp数据包就从网卡到达了用户的缓冲区
阅读(3342) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。UDP IOCP 接收数据 崩溃??-CSDN论坛
UDP IOCP 接收数据 崩溃??
RT&一接收数据程序就崩溃了...&代码如下:(xp&vs08&定位下来是&GetQueuedCompletionStatus&出错了,但是不知道是何原因...)
#include&&Winsock2.h&
#include&&windows.h&
#include&&stdio.h&
#pragma&comment(lib,"ws2_32.lib")
SOCKET global_skt&=&0;
HANDLE global_hIOCP&=&0;
char global_bufRecv[2048]&=&{0};
OVERLAPPED global_ol&=&{0};
void&PostRECV()
WSABUF&wsabuf&=&{0};
wsabuf.buf&=&global_bufR
wsabuf.len&=&sizeof(global_bufRecv);
DWORD&dwFlags&=&0;&
int&iDnsSALen&=&sizeof(sockaddr_in);
sockaddr_in&siDnsRecv&=&{0};
if&(SOCKET_ERROR&==&WSARecvFrom(global_skt,&&wsabuf,&1,&&dwRecv,&&dwFlags,&(sockaddr*)&siDnsRecv,&&iDnsSALen,&&global_ol,&NULL))
printf("WSARecvFrom&err&:&%d\n",&WSAGetLastError());
DWORD&WINAPI&ThreadProc(LPVOID&_lpParameter)
printf("GetCurrentThreadId()&:&%d\n",&GetCurrentThreadId());
PostRECV();
DWORD&dwTrans&=&0,&dwCompletionKey&=&0;
OVERLAPPED*&pol&=&NULL;
int&iRtn&=&GetQueuedCompletionStatus(
global_hIOCP,
&dwCompletionKey,
WSA_INFINITE);
if&(!&iRtn)
int&iErr&=&WSAGetLastError();
printf("GetQueuedCompletionStatus&failed&:&(%d)&%d\n",&::GetCurrentThreadId(),&iErr);
printf("(%d)RECV&:&%s\n",&GetCurrentThreadId(),&global_bufRecv);
PostRECV();
void&main()
WSADATA&wsaData&=&{0};
int&iErr&=&WSAStartup(MAKEWORD(2,2),&&wsaData);
if&(iErr&!=&0)
printf("WSAStartup&err&:&%d&-&%d\n",&iErr,&WSAGetLastError());
global_skt&=&WSASocket(AF_INET,&SOCK_DGRAM,&IPPROTO_IP,&NULL,&0,&WSA_FLAG_OVERLAPPED);
if&(global_skt&==&INVALID_SOCKET)
printf("WSASocket&INVALID_SOCKET&:&%d\n",&WSAGetLastError());
sockaddr_in&si1&=&{0};
si1.sin_family&=&AF_INET;
si1.sin_port&=&htons(9999);
si1.sin_addr.S_un.S_addr&=&INADDR_ANY;
if&(SOCKET_ERROR&==&bind(global_skt,&(sockaddr*)&si1,&sizeof(sockaddr_in)))
printf("bind&SOCKET_ERROR&:&%d\n",&WSAGetLastError());
global_hIOCP&=&CreateIoCompletionPort(INVALID_HANDLE_VALUE,&0,&0,&0);
if&(global_hIOCP&==&0)
printf("CreateIoCompletionPort&INVALID_HANDLE_VALUE&err&:&%d\n",&GetLastError());
HANDLE&hRtn&=&CreateIoCompletionPort((void*)global_skt,&global_hIOCP,&0,&0);
if&(hRtn&==&0)
printf("CreateIoCompletionPort&skt&err&:&%d\n",&GetLastError());
global_ol.hEvent&=&WSACreateEvent();
CreateThread(NULL,&0,&ThreadProc,&NULL,&0,&NULL);
getchar();
检查一下GetQueuedCompletionStatus的传入参数是不是有非法值
引用&1&楼&&的回复:检查一下GetQueuedCompletionStatus的传入参数是不是有非法值
啥叫&非法?
来人啊~&帮帮忙看看啊
up&一下&等待等待
sockaddr_in&siDnsRecv&=&{0};&放全局&试试
引用&5&楼&&的回复:sockaddr_in&siDnsRecv&=&{0};&放全局&试试
定义为全局
&int&iDnsSALen&=&sizeof(sockaddr_in);
&sockaddr_in&siDnsRecv&=&{0};
引用&6&楼&&的回复:引用&5&楼&的回复:
sockaddr_in&siDnsRecv&=&{0};&放全局&试试
定义为全局
&int&iDnsSALen&=&sizeof(sockaddr_in);
&sockaddr_in&siDnsRecv&=&{0};
貌似&确实是这样。
真没往这边想,现在想想,应该是&GetQueuedCompletionStatus&在填写&sockaddr_in&时局部变量失效,是这样的不?
sockaddr_in&siDnsRecv&=&{0};
&&&&if&(SOCKET_ERROR&==&WSARecvFrom(global_skt,&&wsabuf,&1,&&dwRecv,&&dwFlags,&(sockaddr*)&siDnsRecv);
*)&siDnsRecv&使用的是地址,而siDnsRecv&是局部变量,当然会有问题啦
检查一下pol这个值,如果是NULL,返回。
if&(&global_ol&==&pol&)
&&printf("(%d)RECV&:&%s\n",&GetCurrentThreadId(),&global_bufRecv);
&&PostRECV();
if&(&global_ol&==&pol&)
&&printf("(%d)RECV&:&%s\n",&GetCurrentThreadId(),&global_bufRecv);
&&PostRECV();
引用&7&楼&&的回复:引用&6&楼&&的回复:
引用&5&楼&的回复:
sockaddr_in&siDnsRecv&=&{0};&放全局&试试
定义为全局
int&iDnsSALen&=&sizeof(sockaddr_in);
sockaddr_in&siDnsRecv&=&{0};
貌似&确实是这样。
真没往这边想,现在想想,应该是&GetQueuedCompletionStatus……
异步WSARecvFrom的参数lpFrom和lpFromlen,MSDN有说(我是看别人的总结时留意到的),重叠操作前,须保持有效
这两参数放栈里,函数退出了,但WSARecvFrom还会修改栈里数据,可能会覆盖一些其他局部变量,如指针,
更严重的是覆盖函数的返回地址...
As&stated&previously&for&overlapped&sockets,&the&lpFrom&and&lpFromlen&parameters&are&not&updated&until&after&the&overlapped&I/O&has&completed.&The&memory&pointed&to&by&these&parameters&must,&therefore,&remain&available&to&the&service&provider&and&cannot&be&allocated&on&the&application&stack&frame.&
正如重叠套接字之前中,lpFrom和lpFromlen参数不更新,直到后重叠I&/&O已经完成。这些参数指向的内存,因此,必须保持可用的服务提供商,不能分配上的应用程序的堆栈帧。
回复

我要回帖

更多关于 filerecv的中文意思 的文章

 

随机推荐