为什么Socket.AcceptAsync不会触发SocketAsyncEventArgs已完成的事件?

时间:2015-09-27 17:26:35

标签: c# sockets asyncsocket iocp

我正在开发一个服务器应用程序,它将接收消息并做出响应。没什么新鲜的。所以,实际上我关注this answerthis post,但我无法使AcceptAsync()方法触发Completed事件。在互联网上随处搜索,尝试了类似问题的解决方案,但似乎没有什么对我有用。

我还尝试从server.Start()拨打Task.Run(),但没有运气。我知道服务器听起来很好,因为我可以在netstat -an上看到它,如果我在Listen()之后中断,我还可以使用telnet进行连接。

根据我的理解,如果AcceptAsync()方法返回true,它会引发SocketAsyncEventArgs.Completed事件,而事件又将再次调用StartAccept()方法并将循环直到我强行退出。

SocketAsyncEventArgs.Completed也是正确的:http://prntscr.com/8l3x8p,但仍然无效。

这是我的代码:

public class TTSServer
{
    private Socket m_serverSocket;
    private IPEndPoint m_serverEndPoint;

    [DefaultValue(39454)]
    public int Port { get; set; }
    [DefaultValue(100)]
    public int IncommingQueueSize { get; set; }
    [DefaultValue(512)]
    public int BufferSize { get; set; }

    //Listeners to hold event when something happens.

    public static void Main(string[] args)
    {
        TTSServer server = new TTSServer(39454, 100, 512);
        server.Start();
    }

    public TTSServer(int port, int queueSize, int bufferSize)
    {
        Port = port;
        IncommingQueueSize = queueSize;
        BufferSize = bufferSize;
    }


    public void Start()
    {
        Console.WriteLine("Starting TTS Server (Port: {0}, QueueSize: {1}, BufferSize: {2})", Port, IncommingQueueSize, BufferSize);
        m_serverEndPoint = new IPEndPoint(IPAddress.Any, Port);
        m_serverSocket = new Socket(m_serverEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        Console.WriteLine("Binding ({0})", m_serverEndPoint.ToString());
        m_serverSocket.Bind(m_serverEndPoint);
        Console.WriteLine("Listening");
        m_serverSocket.Listen(IncommingQueueSize);

        StartAccept(null);
    }

    public void Stop()
    {

    }

    /// <summary>
    /// Receive a incomming connection attemp in an asynchronous way.
    /// </summary>
    /// <param name="socketEvent">If is null, a new object is created, else, it'll be used for cache friendly reason.</param>
    private void StartAccept(SocketAsyncEventArgs socketEvent)
    {
        //If received reference points to null, let's create a new object.
        if (socketEvent == null)
        {
            Console.WriteLine("Accepting new connections...");
            socketEvent = new SocketAsyncEventArgs();
            socketEvent.Completed += AcceptCompleted; //Add a callback on completed accept incomming connections attemp.
        }
        else
        {
            //Clear current incomming connection socket, so object may be reused.
            socketEvent.AcceptSocket = null;
        }

        //If there is an incomming connection pending(pooled), this method will receive the connection in a async way (witch returns true) 
        //and will call SocketAsyncEventArgs.Completed callback when done. 
        //Else, it waits for a new connection, returns false, and don't won't SocketAsyncEventArgs.Completed callback when done, so we have to 
        //call it manually.
        bool async = true;

        //When I debug this code, async receive true from AcceptAsync.
        async = m_serverSocket.AcceptAsync(socketEvent);

        if (!async)
        {
            AcceptCompleted(this, socketEvent);
        }
    }

    /// <summary>
    /// Handles a incomming connection after it's fully received. This function will do the business logic for incomming connections and prepare
    /// to receive data.
    /// </summary>
    /// <param name="sender">Object who posted this function</param>
    /// <param name="socketEvent">Information of the incomming connection</param>
    private void AcceptCompleted(object sender, SocketAsyncEventArgs socketEvent)
    {
        Connection connection = new Connection(this, socketEvent.AcceptSocket, BufferSize);

        SocketAsyncEventArgs connectedSocketEvent = new SocketAsyncEventArgs();
        connectedSocketEvent.UserToken = connection;

        //Add a receive callback, to be called whenever the Receive function is finished.
        connectedSocketEvent.Completed += FlushBuffer;
        ReceiveData(connectedSocketEvent);

        //Accept next incomming connection.
        StartAccept(socketEvent);
    }

不知道为什么,AcceptCompleted永远不会被解雇,即使AcceptAsync()方法返回true

2 个答案:

答案 0 :(得分:1)

似乎根本原因是默认缓冲:

  

可选地,可以提供缓冲区,其中在ConnectAsync方法成功之后在套接字上接收初始数据块。在这种情况下,需要将SocketAsyncEventArgs.Buffer属性设置为包含要接收的数据的缓冲区,并且需要将SocketAsyncEventArgs.Count属性设置为缓冲区中要接收的最大数据字节数。可以使用SocketAsyncEventArgs.SetBuffer方法设置这些属性。传入的部分缓冲区将在内部使用,供底层Winsock AcceptEx调用使用。这意味着返回的数据量始终小于提供的SocketAsyncEventArgs.Count实例上的System.Net.Sockets.SocketAsyncEventArgs属性值。内部使用的缓冲区数量取决于套接字的地址族。所需的最小缓冲区大小为288个字节。如果指定了更大的缓冲区大小,则Socket将期望除Winsock AcceptEx调用接收的地址数据之外的一些额外数据,并将等待直到收到此额外数据。如果发生超时,则重置连接。因此,如果预期额外数据具有特定数量,则应将缓冲区大小设置为最小缓冲区大小加上此数量。

     

- Socket.AcceptAsync Method (SocketAsyncEventArgs), MSDN

假设不需要缓冲,请禁用缓冲seems to be a solution

SocketAsyncEventArgs args = ...;
args.SetBuffer(null, 0, 0);

答案 1 :(得分:-1)

编辑:在示例中的server.Start之后添加一行阻塞代码。

你会想到改变一条线。

更改此



    !SESSION 2015-09-27 21:25:19.484 -----------------------------------------------
    eclipse.buildId=4.5.0.I20150603-2000
    java.version=1.8.0_60
    java.vendor=Oracle Corporation
    BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US
    Framework arguments:  -product org.eclipse.epp.package.java.product -product org.eclipse.epp.package.java.product
    Command-line arguments:  -os win32 -ws win32 -arch x86 -product org.eclipse.epp.package.java.product -data d:\workspace -product org.eclipse.epp.package.java.product

    This is a continuation of log file D:\workspace\.metadata\.bak_0.log
    Created Time: 2015-09-27 21:28:00.484

    !ENTRY org.eclipse.core.resources 4 2 2015-09-27 21:28:00.484
    !MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.core.resources".
    !STACK 0
    java.lang.NoClassDefFoundError: org/eclipse/mtj/internal/core/util/Utils
        at org.eclipse.mtj.internal.core.util.MTJBuildPropertiesResourceListener.filterResourceDeltas(MTJBuildPropertiesResourceListener.java:169)
        at org.eclipse.mtj.internal.core.util.MTJBuildPropertiesResourceListener.resourceChanged(MTJBuildPropertiesResourceListener.java:91)
        at org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:299)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
        at org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java:289)
        at org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:152)
        at org.eclipse.core.internal.resources.Workspace.broadcastPostChange(Workspace.java:373)
        at org.eclipse.core.internal.resources.Workspace.endOperation(Workspace.java:1470)
        at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2250)
        at org.eclipse.core.internal.events.NotificationManager$NotifyJob.run(NotificationManager.java:43)
        at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

    !ENTRY org.eclipse.core.resources 4 2 2015-09-27 21:28:00.500
    !MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.core.resources".
    !STACK 0
    java.lang.NoClassDefFoundError: org/eclipse/mtj/internal/core/util/ClasspathChangeMonitor$ClassPathVisitor
        at org.eclipse.mtj.internal.core.util.ClasspathChangeMonitor.resourceChanged(ClasspathChangeMonitor.java:97)
        at org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:299)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
        at org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java:289)
        at org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:152)
        at org.eclipse.core.internal.resources.Workspace.broadcastPostChange(Workspace.java:373)
        at org.eclipse.core.internal.resources.Workspace.endOperation(Workspace.java:1470)
        at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2250)
        at org.eclipse.core.internal.events.NotificationManager$NotifyJob.run(NotificationManager.java:43)
        at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

    !ENTRY org.eclipse.jdt.core 4 2 2015-09-27 21:28:00.781
    !MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.jdt.core".
    !STACK 1
    org.eclipse.core.runtime.CoreException: Plug-in org.eclipse.mtj.core was unable to load class org.eclipse.mtj.internal.core.build.MTJCompilationParticipant.
        at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.throwException(RegistryStrategyOSGI.java:194)
        at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:176)
        at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:905)
        at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
        at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:55)
        at org.eclipse.jdt.internal.core.JavaModelManager$CompilationParticipants$1.run(JavaModelManager.java:344)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
        at org.eclipse.jdt.internal.core.JavaModelManager$CompilationParticipants.getCompilationParticipants(JavaModelManager.java:339)
        at org.eclipse.jdt.internal.core.builder.JavaBuilder.initializeBuilder(JavaBuilder.java:589)
        at org.eclipse.jdt.internal.core.builder.JavaBuilder.build(JavaBuilder.java:169)
        at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:734)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
        at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:205)
        at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:245)
        at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:300)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
        at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:303)
        at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:359)
        at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:382)
        at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:144)
        at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:235)
        at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
    Caused by: java.lang.ClassNotFoundException: An error occurred while automatically activating bundle org.eclipse.mtj.core (587).
        at org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:116)
        at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:531)
        at org.eclipse.osgi.internal.loader.ModuleClassLoader.findLocalClass(ModuleClassLoader.java:324)
        at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:327)
        at org.eclipse.osgi.internal.loader.sources.SingleSourcePackage.loadClass(SingleSourcePackage.java:36)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:398)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:352)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:344)
        at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
        at java.lang.Class.getConstructor0(Unknown Source)
        at java.lang.Class.newInstance(Unknown Source)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.loadBundleActivator(BundleContextImpl.java:755)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:706)
        at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:941)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:318)
        at org.eclipse.osgi.container.Module.doStart(Module.java:571)
        at org.eclipse.osgi.container.Module.start(Module.java:439)
        at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:454)
        at org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:107)
        at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:531)
        at org.eclipse.osgi.internal.loader.ModuleClassLoader.findLocalClass(ModuleClassLoader.java:324)
        at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:327)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:402)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:352)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:344)
        at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at org.eclipse.osgi.internal.framework.EquinoxBundle.loadClass(EquinoxBundle.java:573)
        at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:174)
        at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:905)
        at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
        at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:55)
        at org.eclipse.ui.internal.WorkbenchPlugin$1.run(WorkbenchPlugin.java:293)
        at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
        at org.eclipse.ui.internal.WorkbenchPlugin.createExtension(WorkbenchPlugin.java:288)
        at org.eclipse.ui.internal.dialogs.WorkbenchPreferenceNode.createPage(WorkbenchPreferenceNode.java:48)
        at org.eclipse.jface.preference.PreferenceDialog.createPage(PreferenceDialog.java:1300)
        at org.eclipse.ui.internal.dialogs.FilteredPreferenceDialog.createPage(FilteredPreferenceDialog.java:355)
        at org.eclipse.jface.preference.PreferenceDialog.showPage(PreferenceDialog.java:1187)
        at org.eclipse.ui.internal.dialogs.FilteredPreferenceDialog.showPage(FilteredPreferenceDialog.java:608)
        at org.eclipse.jface.preference.PreferenceDialog$9$1.run(PreferenceDialog.java:675)
        at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
        at org.eclipse.jface.preference.PreferenceDialog$9.selectionChanged(PreferenceDialog.java:670)
        at org.eclipse.jface.viewers.StructuredViewer$3.run(StructuredViewer.java:877)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
        at org.eclipse.ui.internal.JFaceUtil$1.run(JFaceUtil.java:50)
        at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:173)
        at org.eclipse.jface.viewers.StructuredViewer.firePostSelectionChanged(StructuredViewer.java:874)
        at org.eclipse.jface.viewers.StructuredViewer.handlePostSelect(StructuredViewer.java:1243)
        at org.eclipse.jface.viewers.StructuredViewer$5.widgetSelected(StructuredViewer.java:1269)
        at org.eclipse.jface.util.OpenStrategy.firePostSelectionEvent(OpenStrategy.java:265)
        at org.eclipse.jface.util.OpenStrategy.access$5(OpenStrategy.java:259)
        at org.eclipse.jface.util.OpenStrategy$1$2.run(OpenStrategy.java:440)
        at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
        at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:135)
        at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4155)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3772)
        at org.eclipse.jface.window.Window.runEventLoop(Window.java:827)
        at org.eclipse.jface.window.Window.open(Window.java:803)
        at org.eclipse.ui.internal.dialogs.WorkbenchPreferenceDialog.open(WorkbenchPreferenceDialog.java:211)
        at org.eclipse.ui.internal.OpenPreferencesAction.run(OpenPreferencesAction.java:63)
        at org.eclipse.jface.action.Action.runWithEvent(Action.java:473)
        at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:595)
        at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:511)
        at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:420)
        at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
        at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4362)
        at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1113)
        at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4180)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3769)
        at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:1127)
        at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
        at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1018)
        at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:156)
        at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:654)
        at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
        at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:598)
        at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
        at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:139)
        at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:380)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:235)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:669)
        at org.eclipse.equinox.launcher.Main.basicRun(Main.java:608)
        at org.eclipse.equinox.launcher.Main.run(Main.java:1515)
    Caused by: org.osgi.framework.BundleException: Exception in org.eclipse.mtj.core.MTJCore.start() of bundle org.eclipse.mtj.core.
        at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:792)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:721)
        at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:941)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:318)
        at org.eclipse.osgi.container.Module.doStart(Module.java:571)
        at org.eclipse.osgi.container.Module.start(Module.java:439)
        at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:454)
        at org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:107)
        ... 93 more
    Caused by: java.lang.NoClassDefFoundError: org/eclipse/osgi/framework/debug/FrameworkDebugOptions
        at org.eclipse.mtj.internal.core.hooks.Debug.(Debug.java:31)
        at org.eclipse.mtj.internal.core.hook.sourceMapper.SourceMapperAccess.setSourceMapper(SourceMapperAccess.java:72)
        at org.eclipse.mtj.core.MTJCore.start(MTJCore.java:490)
        at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:771)
        at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:764)
        ... 100 more
    Caused by: java.lang.ClassNotFoundException: org.eclipse.osgi.framework.debug.FrameworkDebugOptions cannot be found by org.eclipse.mtj.core.hooks_1.0.0.201101310801
        at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:439)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:352)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:344)
        at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 107 more

到此

socketEvent.Completed += AcceptCompleted; //Add a callback on completed accept incomming connections attemp.