C# StreamReader 总是使用 StreamSocketListener 接收 null

问题描述 投票:0回答:1

我试图在 C# 中进行一些测试,但它似乎不起作用,老实说我不明白为什么。 实验是这样的。我在列表中写了一些字符串,然后启动了两个线程:T1 是发送者,T2 是接收者。 T1读取我之前插入的字符串,然后通过T2读取的StreamWriter发送。在该过程结束时,T2 返回它读取的内容,程序终止。 T1 似乎工作正常:它发送数据,然后关闭连接。 T2好像收到了连接,但是没有读取:第一次读取总是null。

有人可以帮助我吗?

这是我的代码:

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.Storage;
using System.Threading;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.Networking;
using Windows.Networking.Sockets;

namespace UWPConsoleApp
{
    class UWPConsoleApp
    {
        static void Main(string[] args)
        {
            List<String> toSend = new List<string>();
            bool end = false;
            do
            {
                Console.WriteLine("Please write something to send to the other task (write ';;;' to end)");
                string s = Console.ReadLine();
                if (s != ";;;")
                {
                    toSend.Add(s);
                    Console.WriteLine($"The list now contains {toSend.Count} lines");
                }
                else
                {
                    if(toSend.Count == 0)
                    {
                        Console.WriteLine("WARNING: you may insert atleast one line before going on");
                        continue;
                    }
                    end = true;
                }
            }
            while (!end);

            List<string> received;
            Task[] tasks =
            {
                Task.Factory.StartNew( () =>
                {
                    ThreadSender ts = new ThreadSender();
                    ts.buffer = toSend;

                    Console.WriteLine("(T1) waiting before starting...");
                    Thread.Sleep(7500);

                    ts.SendInfos();
                } ),
                Task.Factory.StartNew( async () =>
                {
                    ThreadReceiver tr = new ThreadReceiver();
                    received = await tr.ReceiveInfos();
                } )
            };

            Task.WaitAll(tasks);
            Console.WriteLine("Done.");
            Console.ReadKey();
        }
    }

    class ThreadSender
    {
        // buffer di invio
        public List<String> buffer;

        // socket per l'invio dei dati
        private StreamSocket ss;

        public ThreadSender()
        {
            buffer = new List<string>();
            ss = new StreamSocket();
        }

        public async void SendInfos()
        {
            HostName hn = new HostName("localhost");
            await ss.ConnectAsync(hn, "3000");

            StreamWriter sw = new StreamWriter(ss.OutputStream.AsStreamForWrite());
            StreamReader sr = new StreamReader(ss.InputStream.AsStreamForRead());

            Console.WriteLine($"(T1) Sending line count: {buffer.Count}");
            sw.WriteLine(buffer.Count.ToString());
            foreach(string line in buffer)
            {
                Console.WriteLine("(T1) sending line: {0}", line);
                sw.WriteLine(line);
            }

            Thread.Sleep(5000);
            Console.WriteLine("(T1) closing connection");
            ss.Dispose();
            ss = null;
        }
    }

    class ThreadReceiver
    {
        // buffer di scrittura
        public List<String> buffer = new List<string>();

        private StreamSocketListener ssl;
        private bool received = false;
        private bool error = false;

        public ThreadReceiver()
        {
            ssl = new StreamSocketListener();
        }

        public async Task<List<string>> ReceiveInfos() 
        {
            ssl.ConnectionReceived += onConnectionReceived;
            await ssl.BindServiceNameAsync("3000");

            Console.WriteLine("(T2) waiting for connections...");
            while (!received)
            {
                if(error)
                {
                    Console.WriteLine("(T2) closing connection (error occurred)");
                    return null;
                }
                Thread.Sleep(2500);
            }

            return buffer;
        }

        public async void onConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
        {
            Console.WriteLine("received a incoming connection");
            Thread.Sleep(2500);

            StreamReader sr = new StreamReader(args.Socket.InputStream.AsStreamForRead());
            string receivedCountString = await sr.ReadLineAsync();
            if(receivedCountString == null)
            {
                Console.Error.WriteLine("(T2) ERROR: received null value");
                error = true;
                return;
            }
            int nToRead = Int32.Parse(receivedCountString);
            while(nToRead > 0)
            {
                string receivedString = await sr.ReadLineAsync();
                if (receivedString == null)
                {
                    Console.Error.WriteLine("(T2) ERROR: received null value");
                    error = true;
                    return;
                }
                buffer.Add(receivedString);
                nToRead--;
            }

            received = true;
        }
    }
}

以下是上述程序的输出示例:

Please write something to send to the other task (write ';;;' to end)
aaa
The list now contains 1 lines
Please write something to send to the other task (write ';;;' to end)
bbb
The list now contains 2 lines
Please write something to send to the other task (write ';;;' to end)
ccc
The list now contains 3 lines
Please write something to send to the other task (write ';;;' to end)
ddd
The list now contains 4 lines
Please write something to send to the other task (write ';;;' to end)
;;;
(T1) waiting before starting...
(T2) waiting for connections...
received a incoming connection
(T1) Sending line count: 4
(T1) sending line: aaa
(T1) sending line: bbb
(T1) sending line: ccc
(T1) sending line: ddd
(T1) closing connection
(T2) ERROR: received null value
(T2) closing connection (error occurred)
Done.

我正在使用 Windows11 和 Visual Studio 2019 来运行代码(UWP 项目)。

c# uwp
1个回答
0
投票

我看到其他类似的帖子找到了答案。特别是我找到了这个资源,它与我目前正在尝试做的事情有关。

https://social.technet.microsoft.com/wiki/contents/articles/36500.uwp-linux-socket-communication-handling-communciation-in-the-backgroundtask.aspx

我尝试在 VS2019 中使用 C# 在我的本地 PC 上构建一个客户端,并在我的 Linux 服务器计算机(我正在使用 ADA Cloud)上用 Python 构建一个服务器。这在第一次都不起作用:服务器卡住了等待一条消息...... C# 端应该已经发送了。

这是我的服务器:

#!/bin/bash

import socket
import sys

if len(sys.argv) < 2:
        print("USAGE:\n\tserver.py <PORT_NO>")
        sys.exit(1)
HOST = socket.gethostname()
print( f"Hostname is {HOST}" )
PORTNO = int(sys.argv[1])
print( f"port set to {PORTNO}" )

print("opening socket connection...")
sk = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
print( f"trying to open server using \n\tHOST {HOST} \n\tPORTNO {PORTNO}" )
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind( (HOST, PORTNO) )
sk.listen( 4 )
print("OK - listening")

print( "waiting connection..." )
new_socket, new_socket_addr = sk.accept( )
print( "Conenction received!" )

print("waiting for messages...")
data = new_socket.recv(1024)
print( f"received:\n\t{data}" )
new_socket.send(data)
print("Echo done")

new_socket.close()
sk.close()
print("closing...")

这是我的客户:

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using Windows;
using Windows.Networking;
using Windows.Networking.Sockets;

namespace UWPConsoleApp
{
    class UWPConsoleApp
    {
        static void Main(string[] argv)
        {
            string Host = "131.175.205.146";
            string Portno = "5000";

            Console.WriteLine("Trying to connect...");

            StreamSocket ss = new StreamSocket();
            ss.ConnectAsync(new HostName(Host), Portno).AsTask().GetAwaiter().GetResult();

            Console.WriteLine($"Connection Estalished with HOST {Host} PORTNO {Portno}");

            Console.WriteLine("Sending data...");
            StreamWriter sw = new StreamWriter(ss.OutputStream.AsStreamForWrite());
            
            sw.Write("asdiaiHNIUNAHidsi uh aiudnhai i ish i");

            Console.WriteLine("Receiving data...");
            StreamReader sr = new StreamReader(ss.InputStream.AsStreamForRead());
            sr.ReadToEnd();

            Console.WriteLine("OK! Closing...");
            sr.Dispose();
            sw.Dispose();
            ss.Dispose();
        }
    }
}

我注意到每次调用 Write() 时,该网站中的代码片段都会启动 Flush()。好吧,我试过了……而且成功了!

// before
sw.Write("asdiaiHNIUNAHidsi uh aiudnhai i ish i");

// after
sw.Write("asdiaiHNIUNAHidsi uh aiudnhai i ish i");
sw.Flush();

嗯……我试过用这种方式更新上面的代码,然后……哦!它奏效了。

这是代码的最终版本:

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.Storage;
using System.Threading;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.Networking;
using Windows.Networking.Sockets;

namespace UWPConsoleApp
{
    class UWPConsoleApp
    {
        static void Main(string[] args)
        {
            List<String> toSend = new List<string>();
            bool end = false;
            do
            {
                Console.WriteLine("Please write something to send to the other task (write ';;;' to end)");
                string s = Console.ReadLine();
                if (s != ";;;")
                {
                    toSend.Add(s);
                    Console.WriteLine($"The list now contains {toSend.Count} lines");
                }
                else
                {
                    if (toSend.Count == 0)
                    {
                        Console.WriteLine("WARNING: you may insert atleast one line before going on");
                        continue;
                    }
                    end = true;
                }
            }
            while (!end);

            List<string> received;
            Task[] tasks =
            {
                Task.Factory.StartNew( () =>
                {
                    ThreadSender ts = new ThreadSender();
                    ts.buffer = toSend;

                    Console.WriteLine("(T1) waiting before starting...");
                    Thread.Sleep(7500);

                    ts.SendInfos();
                } ),
                Task.Factory.StartNew( async () =>
                {
                    ThreadReceiver tr = new ThreadReceiver();
                    received = await tr.ReceiveInfos();
                } )
            };

            Task.WaitAll(tasks);
            Console.WriteLine("Done.");
            Console.ReadKey();
        }
    }

    class ThreadSender
    {
        // buffer di invio
        public List<String> buffer;

        // socket per l'invio dei dati
        private StreamSocket ss;

        public ThreadSender()
        {
            buffer = new List<string>();
            ss = new StreamSocket();
        }

        public async void SendInfos()
        {
            HostName hn = new HostName("localhost");
            await ss.ConnectAsync(hn, "3000");

            StreamWriter sw = new StreamWriter(ss.OutputStream.AsStreamForWrite());
            StreamReader sr = new StreamReader(ss.InputStream.AsStreamForRead());

            Console.WriteLine($"(T1) Sending line count: {buffer.Count}");
            sw.WriteLine(buffer.Count.ToString());
            sw.Flush();
            foreach (string line in buffer)
            {
                Console.WriteLine("(T1) sending line: {0}", line);
                sw.WriteLine(line);
                sw.Flush();
            }

            Thread.Sleep(5000);
            Console.WriteLine("(T1) closing connection");
            ss.Dispose();
            ss = null;
        }
    }

    class ThreadReceiver
    {
        // buffer di scrittura
        public List<String> buffer = new List<string>();

        private StreamSocketListener ssl;
        private bool received = false;
        private bool error = false;

        public ThreadReceiver()
        {
            ssl = new StreamSocketListener();
        }

        public async Task<List<string>> ReceiveInfos()
        {
            ssl.ConnectionReceived += onConnectionReceived;
            await ssl.BindServiceNameAsync("3000");

            Console.WriteLine("(T2) waiting for connections...");
            while (!received)
            {
                if (error)
                {
                    Console.WriteLine("(T2) closing connection (error occurred)");
                    return null;
                }
                Thread.Sleep(2500);
            }

            Console.WriteLine("(T2) All Received! Closing...");
            return buffer;
        }

        public async void onConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
        {
            Console.WriteLine("(T2) received a incoming connection");
            Thread.Sleep(2500);

            StreamReader sr = new StreamReader(args.Socket.InputStream.AsStreamForRead());
            string receivedCountString = await sr.ReadLineAsync();
            if (receivedCountString == null)
            {
                Console.Error.WriteLine("(T2) ERROR: received null value");
                error = true;
                return;
            }
            int nToRead = Int32.Parse(receivedCountString);
            
            Console.WriteLine($"(T2) Receiving {nToRead} messages...");
            while (nToRead > 0)
            {
                string receivedString = await sr.ReadLineAsync();
                if (receivedString == null)
                {
                    Console.Error.WriteLine("(T2) ERROR: received null value");
                    error = true;
                    return;
                }
                else
                    Console.WriteLine($"(T2) Received string: {receivedString}");
                buffer.Add(receivedString);
                nToRead--;
                Console.WriteLine($"Remaining {nToRead} messages");
            }

            received = true;
        }
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.