微软异步服务器套接字示例 [英] Microsofts Asynchronous Server Socket Example

查看:104
本文介绍了微软异步服务器套接字示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于一个问题<一href=\"http://stackoverflow.com/questions/5815872/asynchronous-server-socket-multiple-clients\">this问题(异步服务器套接字多个客户端)。

I have a question regarding this question ("Asynchronous server socket multiple clients").

无论是微软改变的例子因为格鲁斯答案或者我真不弄不明白 -
在本例中它说:

Either Microsoft changed the example since Groos answer or I really don't get it - in the example it says:

        while (true) {
            // Set the event to nonsignaled state.
            allDone.Reset();

            // Start an asynchronous socket to listen for connections.
            Console.WriteLine("Waiting for a connection...");
            listener.BeginAccept( 
                new AsyncCallback(AcceptCallback),
                listener );

            // Wait until a connection is made before continuing.
            allDone.WaitOne();
        }

据我了解BeginAccept()函数contiuously在while(true)循环调用,只能通过和直到AcceptCallback()函数被调用被停止,因为那里发生的第一件事就是allDone.Set()。

As I understand the BeginAccept() function is called contiuously in the while(true) loop, only being stopped by and until the AcceptCallback() function is called, because the first thing that happens there is allDone.Set().

但Groo说

和MSDN例子的问题是,它允许只有一个客户端的连接(listener.BeginAccept称为仅一次)。

The problem with MSDN example is that it allows connection of only a single client (listener.BeginAccept is called only once).

而实际上我不知道为什么ManualResetEvent的的 allDone 的是在所有使用...
我以为listener.EndAccept(AR)方法阻止反正

And actually I don't get why the ManualResetEvent allDone is used at all... And I thought the listener.EndAccept(ar) method is blocking anyways.

时listener.BeginAccept()抛出一个异常,如果调用,同时还在运行第二次?
但如果是这样,为什么allDone.Set()是前listener.EndAccept(AR)?

Is listener.BeginAccept() throwing an exception if called a second time while still running ? But if so why allDone.Set() is before listener.EndAccept(ar)?

和另一个问题:

我可以只调用handler.BeginReceive(...),在ReadCallback(IAsyncResult的AR)功能,我收到后的 EOF 的,等待来自同一客户端更多的数据进来的?

Can I just call handler.BeginReceive(...), in the ReadCallback(IAsyncResult ar) function after I received a EOF, to wait for more incomming data from the same client?

任何人有更多的经验可以解释给我,好吗?

Can anybody with more experience explain that to me, please?

谢谢!

推荐答案

这有可能是在事实上更新的例子,因为其他SO答案被张贴。或者,它可能回答者Groo根本没有完全理解的例子自己。在这两种情况下,你是正确的观察,他的发言,只有一个客户端可以永远接受不正确。

It's possible the example was in fact updated since that other SO answer was posted. Or it's possible the answerer Groo simply did not fully understand the example himself. In either case, you are correct to observe that his statement that only one client can ever be accepted is incorrect.

我同意一些什么USR写的,但对整个事情有些不同的看法。另外,我觉得这些问题应该得到更多的COM prehensive和针对性治疗。

I agree with some of what usr wrote, but have a somewhat different take on the whole thing. Also, I think the questions deserve more comprehensive and specific treatment.

首先,虽然我同意这是具有优良设计一般要发出后续调用BeginAccept()在接受回调方法,而不是使用一个循环,没什么每错本身与在实施例的实施。到 BeginAccept没有新的呼叫()由直到在previous电话会议结束后,被通知;事件句柄是用来线程,其中 BeginAccept()被调用线程为准卷起操作同步完成。第一个线程才会被释放时previously发行的接受完成,然后只有一个新的呼叫到 BeginAccept()再次的线程块之前完成。

First, while I agree that it is superior design generally to issue subsequent calls to BeginAccept() in the accept callback method rather than using a loop, there's nothing wrong per se with the implementation in the example. No new call to BeginAccept() is made until the after completion of the previous call has been signaled; the event handle is used to synchronize the thread where BeginAccept() is called with whichever thread winds up handling the completion. The first thread is released only when the previously-issued accept completes, and then only one new call to BeginAccept() is made before that thread blocks again.

这是一个有点尴尬,但完全洁净。这有可能是该样本的作者推测,既然在他的控制台程序,他将有一个线程坐在那里闲着,无论如何,他还不如给它的东西做的。 :)

It's a bit awkward, but completely kosher. It's possible that the author of that sample figured that since in his console program, he was going to have a thread sitting there idle anyway, he might as well give it something to do. :)

总之,回答问题1:你是正确的,这个例子目前美元,该链接p $ psent确实允许多个客户端连接。

Anyway, to answer question #1: you are correct, the example currently present at that link does allow multiple clients to connect.

问题2,为什么手柄使用的事件,我希望上述的解释了我们答案。这是什么示例使用释放被调用线程 BeginAccept(),这样才可以称之为另一次一次的previous调用完成。

Question #2, why is the event handle used, I hope the above explanation has answered that. It's what the example uses to release the thread which is calling BeginAccept(), so that it can call it another time once the previous call has completed.

问题3, EndAccept()阻止?有点。如果你调用 EndAccept()在接受手术之前已实际完成,然后是。这将阻止。但在这种情况下,它被称为仅当完成回调已被调用。在这一点上,我们可以肯定的是,在调用 EndAccept()将的的块。所有它要做的是在这一点上(假定没有例外,当然)检索完成操作的结果。

Question #3, EndAccept() is blocking? Sort of. If you call EndAccept() before the accept operation has actually completed, then yes. It will block. But in this case, it's being called only when the completion callback has been called. At this point, we can be certain that the call to EndAccept() will not block. All it's going to do is retrieve the result of the completed operation at that point (assuming no exceptions, of course).

问题#4,它是合法的,叫 BeginAccept()第二次,之前 EndAccept()有被称为?是的,即使它是不合法的,有多个接受操作排队(它是)。在这里,调用 BeginAccept()发生在完成回调的第一个 BeginAccept()。也就是说,当code已经不叫 EndAccept()然而,接受手术本身的的完成,所以它甚至不是一个有多个的情况下,接受优秀的操作。接收和发送操作是类似宽松;你可以多次一个完成任何已经发生法律之前调用所有的这些方法。

Question #4, is it legal to call BeginAccept() a second time, before EndAccept() has been called? Yes, even if it were not legal to have multiple accept operations queued up (which it is). Here, the call to BeginAccept() happens in the completion callback for the first BeginAccept(). That is, while the code hasn't called EndAccept() yet, the accept operation itself has completed and so it's not even a case of having multiple accept operations outstanding. Receive and send operations are similarly liberal; you can legally call all of those methods multiple times before a completion for any has happened.

问题5,我可以叫 BeginReceive()尽管我已经收到&LT; EOF&GT; ?是。事实上,这是其中MSDN例子的是一个面积的有缺陷的,因为它的的继续接收一旦最后一个预期的数据已经收到。实际上,直到0字节接收完成对仍应始终调用 BeginReceive()再次,更多的数据是否预期,然后处理已完成接收,其中字节计数为0调用关机(SocketShutdown.Both)在这一点上信号连接的优雅关闭的确认(假设它的完成由点发送,当时它早就叫关机(SocketShutdown.Send) ...如果不是,它应该只使用 SocketShutdown.Receive 和/或只是不调用shutdown在所有直到把它完成发送和它可以使用 SocketShutdown.Both ... SocketShutdown.Receive 实际上并没有做任何事情来连接本身显著,所以这是合理的只是等待,直到 SocketShutdown.Both 为宜)。

Question #5, can I call BeginReceive() even though I've received <EOF>? Yes. In fact, this is an area in which the MSDN example is flawed, in that it does not continue receiving once the last of the expected data has been received. In actuality, until a receive completes with 0 bytes it should still always call BeginReceive() again, whether or not more data is expected, and then handle a completed receive where the byte count is 0 by calling Shutdown(SocketShutdown.Both) at that point to signal acknowledgement of the graceful closure of the connection (assuming it's done sending by that point, at which time it would have already called Shutdown(SocketShutdown.Send)...if not, it should just use SocketShutdown.Receive and/or just not call Shutdown at all until it's done sending and it can use SocketShutdown.Both...SocketShutdown.Receive doesn't actually do anything significant to the connection itself, so it's reasonable to just wait until SocketShutdown.Both is appropriate).

在换句话说,即使服务器的糊涂账的客户端不会发送任何额外的数据,正确使用套接字API是仍然尝试另一个接收操作,查找0字节的返回值,指示该客户端具有实际上开始关闭的连接。只有在这一点上应该在服务器开始自己的关机过程,并关闭套接字。

In other words, even if the server knows for sure the client isn't going to send any additional data, correct use of the socket API is to still attempt another receive operation, looking for that 0-byte return value that indicates that the client has in fact started to shutdown the connection. Only at that point should the server begin its own shutdown process and close the socket.

最后,你也没问,而是因为USR提出来的:我不同意这个MSDN比如今天有没有相关性。不幸的是,微软并没有为插座类提供了一个异步API的基于任务的版本。有的支持其它网络的API异步/的await(如的TcpClient / 的NetworkStream ),但如果你想直接使用插座类,你坚持与老款异步(插座有两个,无论是回调为主)。

Finally, you didn't ask but because usr brought it up: I disagree that this MSDN example has no relevance today. Unfortunately, Microsoft didn't provide a Task-based version of an async API for the Socket class. There are other network APIs that support async/await (e.g. TcpClient/NetworkStream), but if you want to use the Socket class directly, you're stuck with the old async models (Socket has two, both callback-based).

您可以包装在任务同步插座方法来替代旧的API,但你' ð失去在Socket类基于端口的I / O完成异步API的优势。更好的是某种任务兼容的封装中仍然使用异步API下,但是这较为复杂,实施和我此刻不知道这样的事情(但它肯定会存在,所以这可能是你的一部分值得一位网络搜索,如果你想preFER使用异步/的await)。

You could wrap the synchronous Socket methods in Tasks as an alternative to the older API, but then you'd lose the advantage of the I/O completion port-based asynchronous API in the Socket class. Much better would be some kind of Task-compatible wrapper that still uses the asynchronous API underneath, but that's somewhat more complicated to implement and I'm not aware of such a thing at the moment (but it certainly could exist, so that might be worth a bit of web-searching on your part if you'd prefer to use async/await).

希望帮助!我的答案很长很抱歉,但它是一个pretty广泛的问题(几乎太广,但对我来说似乎仍然在合理的范围SO :))。

Hope that helps! I'd apologize for the long answer, but it was a pretty broad question (almost too broad, but to me it seemed still within reasonable SO bounds :) ).

这篇关于微软异步服务器套接字示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆