解决方案 »
- VC中按钮控制复选框的疑问?
- 想实现vpn服务器,不知道需要知道那些东西.具体想实现功能如下.请大人指导!
- 求助:向各位大哥请教两个基础问题,谢谢!
- VB调用VC写的DLL的时候,不能使用DLL里面定义的函数,怎么办?在线等!!急啊急!!!!
- 如何在视图中获得滚动条的位置信息,50分求解
- 请问怎样调整CListCtrl中每行的的行间距?
- WH_GETMESSAGE钩子不能拦截WM_DESTROYt和WM_CREATE消息吗!?
- 很容易赚分的小问题
- SDI 启动的时候 莫名的弹出一个新建对话框,点确定才能继续
- 请问:什么叫sdk,这与基于mfc的应用开发有何区别?
- VS2005的错误,帮看看什么意思?
- !!!!!!!如果数据全满的情况下,最普通的recv/send套接字操作快,还是完成例程快
这样的解说和选择事件模式一致——当有事件来时,如果总数据有100K,只取30K,那剩下的70K不会有事件通知!2。由于wsarecv存在不能一次把给定的数据发送完成的可能,需要在发送完成的时候做判断再发送剩下的。。那如果在发送完成之前需要发送另一个数据包的话,不是乱套了?第一个数据包给这个数据包隔开了。这时候是不是需要建立一个发送队列?只有确定前面一个包完成时才能发送另一个包?
收:发起一个完成例程的事件,当收到数据后,完成端口的线成get到这个状态,然后进行操作
发:放入一个事件,完成端口get这个事件状态后,进行发送的代码执行。这个所有的中间,有个KEY,就相当是你的参数地址。
1、如果第一次GetXXX返回,Socket有数据并大于你投递的缓存的时候,会填满你投递的缓存,剩下的会等你再次投递WSARecv,WSARecv在异步情况下,应该不会不会立即获取数据,理论上应该由GetXXX返回。这种情况只有单投递接收的时候才会产生你题的这个问题,而对于多投递接收,没有发现这种情况。关于你题的这个我仅能从理论上回答,你可以测试单投递,一次发超过投递缓存大小的数据,在GetXXX之后看看WSARecv返回是否已经获得缓冲数据。2、WSARecv最大只能填充投递的缓存,剩下由Socket约8K的缓存存放。一般情况下,需要你设置投递缓存小于Socket缓存,如果大于的,应该分包。或者你设置Socket缓存为0,并多次投递WSARecv保证不发生饥渴。对于粘包分包等处理,不是Iocp所能完成的,也不是Socket能完成的,需要你有一套完整的协议。
另外,不知道你的协议为什么要先发数据头,这样的效率反而降低了Iocp的性能,我们通常做法是一次发完一个完整的数据包(包头+数据+包尾)。
如果你不先发包头的话。假设这样一个情况。对方发送一个超过你接收buffer大小的包过来,那你怎么处理。
只是返回的Key的可能是最后一个绑定的Key,前面绑定的应该失效了吧。不会说,我先后绑两个Key,同一个事件,会触发两次GetXXX返回吧?权威说法期待中...
恩,我知道这时候缓冲区肯定有数据,,问题是出在getqueuexxx这函数什么情况下会返回核心编程》上提到内核有一个完成队列,这个队列有通知元素的时候,getqueuexxx就返回,但你第一次getqueuexxx返回取到包头后,同时也把这个队列的通知元素取走了。这样你再想wsarecv数据体的时候,
getqueuexxx由于队列没通知元素就没能取成功。具体你可以找那本书来看下,我觉得说得也有道理,不过也可能我理解错误
Socket和Iocp只管收发。
你完全没有理解掉线和Logout在游戏中的重要性
对方发送一个超过你接收buffer大小的包过来,那你怎么处理。 首先回答你这个问题,超过buffer,TCP是保证发的有多少,就能收到多少,比如缓冲区 8K,你发了10K,剩下2K待发,直到你前面8K收完为止。你收的函数就可能这样
while( len==lenRecv )
lenRecv+=recv();..你再想wsarecv数据体的时候不是有产生一个事件通知了吗?不就又get到数据了。完成端口是以完成例程为基础衍生的,而windows里的异步事件都是有一个事件由系统主动通知的。那本书上不是也说吗:
你可以放入一个消息post
也可以因为完成一个I/O操作而在队列增加。 完成端口怎么知道这个事件操作,就是因为有事件通知。不信你在WSArevc的时候,把overlapped参数设置为空,看看能不能get到东西
你不明白游戏是怎么处理的。
套接字的四个关键字:服务器 IP port,客户端ip port
如果是异常掉线的,你觉得客户端IP会一样吗?即使一样,port会一样吗?port有保护机制,你去研究下tcp断开的四次握手,为什么有个wait的状态。
请记住,游戏正在进行时,掉线是不能立即删除这个用户对象的,只能删除这个Socket的句柄对象。
只有用户发送Logout方可删除,或掉线超时了也可认为是Logout了(部分棋牌游戏会将他转入托管状态,如果在游戏结束之前他在上线了还可以继续游戏)。你答非所问。
除非你保证,掉线后再连接也是同一个Socket。
我Q 2#4#2#1#0#6#7#6#4#
你说的是TCP吗?TCP的特性就是这样啊。流结构,,随意的合在一起。所以才有数据头的概念。
文中我已经很明确的说了:
做过Tcp服务开发的人都知道,每个客户端连接都有一个Socket对象(下称HandleData)与之对应。做过游戏开发的人也肯定知道,在服务器端每个登录的用户有个对象(下称UserData)记录用户信息,UserData和HandleData也是一一对应关系。但两者很难合并为一体(同一个数据结构或类对象),UserData是在用户输入ID和密码Login之后被会创建(或池分配),用户发送数据Logout之后会被摧毁(或回收入池),而在Logout之前,由于网络等诸多原因,会有N次的重新连接的可能性,如果断线不超过规定时间的话UserData是不能摧毁的,那么UserData在其生命期内对应的HandleData就不是唯一的了。一般HandleData和UserData关联的做法是,根据Login的用户ID在目前的在线用户信息列表中查找UserData,找到则关联(未超时和Logout),找不到则创建后再关联,此后根据关联信息无需遍历很快就可以知道来自这个HandleData的数据就是这个UserData的(用户登录频率远比数据收发频率底得多,以最快方式把Socket的数据定位到用户对象上去是高效率的一个关键)后面说:
尚未不知道有人提过这个方法,也不知道是否行得通,也希望大家互相探讨。
....
对这句我说一下
有自称内核编程的人说临界段同步不要需要进入内核态,用过临界段的人都知道,当竞争发生的时候,“后来”的线程总被挂起,那么线程挂起会进入什么态? 我不知道windows得临界段同步是否会进入内核态,但是,如果说不进入内核态,指的是没有竞争发生得时候。如果是要被挂起得线程,那是一定会进入内核态得,毕竟线程调度是内核态完成得。这里说得一定不包括自旋锁,或者一些非系统定义得线程(比如一些库里面会提供用户态模拟得线程调度).
另外竞争失败得线程要进入内核态带来得性能损耗一般是可以忽略得,毕竟,都竞争失败了,你不让他进内核态睡眠,你想让他继续占CPU?
那是一个反问方式的回答而已。刚好,请教你个个问题:
InterlockedIncrement和InterlockedDecrement,InterlockedPopEntrySList,
InterlockedPopEntrySList是如何处理竞争的?是使用类似Lockfree的死Loop等待,还是其它更好的线程挂起等待方式?在测试中总发现System进程的CPU使用很高,总感觉是上诉锁的问题,当然也不排除内核处理Icop机制和收发数据。
如果安全点需要CRC之类的验证。应为会有数据区的数值与(包头或包尾)一致。
如果发现包头,根据包长度,验证包尾是否合法,合法则解析数据,并移动指针到包尾之后,如何还有数据再验证是否是包头...
如果发现包头没有发现包尾,则需要保存,等待下个数据包并与之合并,再寻找包头和包尾...
恩,搞清楚了。那另外有一个写操作的问题。就是wsasend,有可能wsasend不完整。这情况难道只能建立一个队列,把要send的数据丢进这队列,然后在确定前一包全部发送成功,再出队下个包发送?这样效率会不会低了?但如果不是这样,还能怎样?
这个就和上面问题对应,解决这个,上一个就不会出现。
7C809776 mov ecx,dword ptr [esp+4]
7C80977A mov eax,1
7C80977F lock xadd dword ptr [ecx],eax
7C809783 inc eax
7C809784 ret 4
EnterCriticalSection();
7C921005 mov ecx,dword ptr fs:[18h]
7C92100C mov edx,dword ptr [esp+4]
7C921010 cmp dword ptr [edx+14h],0
7C921014 jne 7C921065
7C921016 lock inc dword ptr [edx+4]
7C92101A jne 7C921035
7C92101C mov eax,dword ptr [ecx+24h]
7C92101F mov dword ptr [edx+0Ch],eax
7C921022 mov dword ptr [edx+8],1
7C921029 xor eax,eax
7C92102B ret 4 LeaveCriticalSection();
7C9210ED mov edx,dword ptr [esp+4]
7C9210F1 xor eax,eax
7C9210F3 dec dword ptr [edx+8]
7C9210F6 jne 7C92111E
7C9210F8 mov dword ptr [edx+0Ch],eax
7C9210FB lock dec dword ptr [edx+4]
7C9210FF jge 7C921104
7C921101 ret 4 2者用的方式一样,VC08 debug无优化模式lock解释:
摘:
LOCK总线封锁信号,三态输出,低电平有效。LOCK有效时表示CPU不允许其它总线主控者占用总线。这个信号由软件设置,当前指令前加上LOCK前缀时,则在执行这条指令期间LOCK保持有效,阻止其它主控者使用总线。 摘
从 P6 处理器开始,如果指令访问的内存区域已经存在于处理器的内部缓存中,则“lock” 前缀并不将引线 LOCK 的电位拉低,而是锁住本处理器的内部缓存,然后依靠缓存一致性协议保证操作的原子性。4.2) IA32 CPU调用有lock前缀的指令,或者如xchg这样的指令,会导致其它的CPU也触发一定的动作来同步自己的Cache。
CPU的#lock引脚链接到北桥芯片(North Bridge)的#lock引脚,当带lock前缀的执行执行时,北桥芯片会拉起#lock
电平,从而锁住总线,直到该指令执行完毕再放开。 而总线加锁会自动invalidate所有CPU对 _该指令涉及的内存_
的Cache,因此barrier就能保证所有CPU的Cache一致性。4.3) 接着解释。
lock前缀(或cpuid、xchg等指令)使得本CPU的Cache写入了内存,该写入动作也会引起别的CPU invalidate其Cache。
IA32在每个CPU内部实现了Snoopying(BUS-Watching)技术,监视着总线上是否发生了写内存操作(由某个CPU或DMA控
制器发出的),只要发生了,就invalidate相关的Cache line。 因此,只要lock前缀导致本CPU写内存,就必将导致
所有CPU去invalidate其相关的Cache line。
http://www.unixresources.net/linux/clf/linuxK/archive/00/00/65/37/653778.html
http://www.bitscn.com/linux/kernel/200806/144491_2.html 蓝色字取自看雪。看懂看不懂就看自己RP了。
可以说竞争的时候,后来者的操作是无效的?那么后来者如何才能再次操作,直到他获得成功为止?或者说,lock前缀是让所有CPU串行化,不会在同一个时间内操作?主要是这个问题。
这个很简单啊。当被锁住的时候(从 P6 处理器开始,如果指令访问的内存区域已经存在于处理器的内部缓存中,则“lock” 前缀并不将引线 LOCK 的电位拉低,而是锁住本处理器的内部缓存,然后依靠缓存一致性协议保证操作的原子性。 ),线程必然要不断的检测是否符合条件。 而这个繁忙度就取决于你线程的优先级别
EnterCriticalSection 发生竞争后跳转到的地方,应该就是处理竞争进入内核态的。
看来,使用InterLocked还要考虑很多了。
要看服务器的CPu数量了。曾经有人极力推荐内核链栈:Singly-Linked list
也就是:InterlockedPopEntrySList
我在2CPU的机子上测试过,比临界端块N多。我也查了很多资料,但说如何解决竞争等待问题,还是不很明白。
现在似乎明白了。
由于每个申请自旋锁的处理器均在全局变量 slock 上忙等待
”这就是明白的关键了。我总以为可以串行化CPU时钟周期或者令CPU时钟停止直到获得控制权,从而达到等待目的呢。
谢谢楼上贴汇编的 EnterCriticalSection应该是没竞争就只是锁了一下总线 有竞争就通过系统调用进内核态睡觉去 另外LEAVE的时候也有可能要进内核态唤醒别的线程
Windows核心编程第五版P212:
当线程试图进入一个关键段,但这个关键段正被另一个线程占用的时候,函数会立即把调用线程切换到等待状态,意味着线程必须从用户模式切换到内核模式。