草庐IT

c# - 服务器和客户端之间通过TCP异步传输数据

coder 2023-09-19 原文

我有一个问题:服务器没有从客户端接收到任何数据。

这是服务器初始化:

public void Start()
{
    var listener = new TcpListener(IPAddress.Any, Port);
    listener.Start();
    Task.Run(
        async () =>
        {
            while (!this.cancellationToken.IsCancellationRequested)
            {
                var client = await listener.AcceptTcpClientAsync();
                var stream = client.GetStream();
                string request = await ReceiveRequestAsync(stream);
                await RequestHandlerAsync(request, stream);
            }

            listener.Stop();
        }, this.cancellationToken);
}

这里是请求客户端代码(它来自单元测试,所以服务器在这里初始化):

var server = new SimpleFtpServer();
server.Start();
using (TcpClient client = new TcpClient(RequestUri, Port))
{
        NetworkStream stream = client.GetStream();
        StreamWriter writer = new StreamWriter(stream)
        {
            AutoFlush = true,
        };
        writer.Write("zapros");

        using (StreamReader reader = new StreamReader(stream))
        {
            Console.Writeline(reader.ReadToEnd());
        }
}

server.Stop();

值得一提的是,我最近才真正开始在 C# 中学习 async/await,所以问题可能出在它们的使用上。

提前致谢!

最佳答案

它可能并不完美,但我和你处于同样的情况,并创建了一个异步 TCP 客户端/服务器来进行练习和实验。

下面是我的实现的摘录,它有效

服务器:

public class AsyncServerDemo
{
    private CancellationTokenSource cancel;
    private readonly TcpListenerEx listener;

    private Task WaitingForConnections;

    private Timer timerCallAcceptClients;

    public bool IsRunning { get; private set; }

    public AsyncServerDemo(int port)
    {
        cancel = new CancellationTokenSource();
        listener = new TcpListenerEx(IPAddress.Any, port);
    }
    private Task<string> WaitForMessageAsync(TcpClient client, CancellationToken token)
    {
        return Task.Run(() =>
        {
            StringBuilder sb = new StringBuilder();
            bool dataAvailable = false;
            while (!token.IsCancellationRequested)
            {
                while (client.Client.Available > 0)
                {
                    dataAvailable = true;
                    int buffered = client.Client.Available;
                    byte[] buffer = new byte[buffered];
                    client.Client.Receive(buffer);
                    sb.Append(Encoding.ASCII.GetString(buffer));
                }

                if (dataAvailable)
                {
                    dataAvailable = false;
                    return sb.ToString();
                }
            };
            return string.Empty; //timeout
        });
    }
    private Task AcceptClientAsync()
    {
        return Task.Factory.StartNew(async () =>
        {
            IsRunning = true && !cancel.IsCancellationRequested;
            while (!cancel.IsCancellationRequested)
            {
                if (!listener.Pending())
                {
                    continue;
                }

                TcpClient newClient = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
                Stopwatch timeout = new Stopwatch();
                timeout.Restart();
                string message = await WaitForMessageAsync(newClient, new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);
                if (message != null)
                {
                    //TODO: Message recieved
                }
                timeout.Stop();
            }
        });
    }

    public void Start()
    {
        listener.Start();
        timerCallAcceptClients = new Timer(new TimerCallback((state) =>
        {
            AcceptClientAsync();
        }), null, 0, (int)TimeSpan.FromSeconds(1).TotalMilliseconds);
    }
    public async void Stop()
    {
        if (!IsRunning) return;


        using (cancel)
            cancel.Cancel();

        timerCallAcceptClients.Dispose();
        if (WaitingForConnections != null)
            await WaitingForConnections;

        cancel = null;

        listener.Stop();
        IsRunning = false;
        cancel = new CancellationTokenSource();
    }

}

客户:

public class ClientExDemo
{
    private Task<string> WaitForMessage;
    private NetworkStream currentStream;
    private CancellationTokenSource messageToken;
    public EventHandler<ClientEx> OnServerFound;


    public TcpClient Connection;
    public EventHandler<string> OnMessage;


    public async Task StartListenAsync(CancellationTokenSource token = null)
    {
        if (token == null)
            messageToken = new CancellationTokenSource();
        else
            messageToken = token;

        currentStream = Connection.GetStream();
        string message = "";


        if (message.Length > 0)
            OnMessage?.Invoke(this, message);

        if (!messageToken.IsCancellationRequested)
        {
            await StartListenAsync(token);
        }

        Timeout();
    }
    protected virtual void Timeout()
    {

    }
    public async Task WaitForServerAsync(string ip, int port)
    {
        do
        {
            try
            {
                await Connection.ConnectAsync(ip, port);
            }
            catch (SocketException x)
            {

            }
            await Task.Delay(50);
        } while (!Connection.Connected);

    }

    public void StopListen()
    {
        using (messageToken)
        {
            messageToken.Cancel();
        }

        try
        {

            WaitForMessage.GetAwaiter().GetResult();
        }
        catch (AggregateException)
        {

        }


        currentStream.Close();

        messageToken = null;
        currentStream = null;
        WaitForMessage = null;
    }

    public ClientExDemo()
    {
        Connection = new TcpClient();

        OnServerFound += ServerFound;
    }
    private void ServerFound(object sender, ClientEx args)
    {

    }
    public void Send(string message)
    {
        Connection.Client.Send(Encoding.ASCII.GetBytes(message));
    }


}

您可以在一个简单的控制台应用程序中从客户端发送消息:

        ClientEx client= new ClientEx();

        await client.WaitForServerAsync(ip, port);


        string msg = string.Empty;

        do
        {
            Console.Write("Send Message: ");
            msg = Console.ReadLine();
            shell.Send(msg);
        } while (msg != "q");

        Console.WriteLine();
        Console.WriteLine("BYE");
        Console.ReadKey();

关于c# - 服务器和客户端之间通过TCP异步传输数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53250404/

有关c# - 服务器和客户端之间通过TCP异步传输数据的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  4. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  5. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  6. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  7. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  8. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  9. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  10. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

随机推荐