c#中tcp异步编程遇到异常问题,新手感觉很不得懂 希望大神能从浅显的角度帮我解答

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c#中tcp异步编程遇到异常问题,新手感觉很不得懂 希望大神能从浅显的角度帮我解答相关的知识,希望对你有一定的参考价值。

//发起连接请求
private void ConnectoServer()

AsyncCallback requestcallback = new AsyncCallback(RequestCallBack);
statusStripInfo.Invoke(shwStatusInfoCallBack, "正在连接...");
statusStripInfo.Invoke(shwProgressProcCallBack, 1);
//tcpClient = new TcpClient(AddressFamily.InterNetwork);//获得本机的ip地址
tcpClient = new TcpClient(host,52888);
//tcpClient = new Socket(AddressFamily.InterNetwork,);
IAsyncResult result = tcpClient.BeginConnect(IPAddress.Parse(tbxSrvIp.Text), int.Parse(tbxPort.Text), requestcallback, tcpClient); //异步操作1
注:host是在之前定义过的一个ip地址
这个一个客户端的部分代码,源代码本来是:
//tcpClient = new TcpClient(AddressFamily.InterNetwork);//获得本机的ip地址。
运行时没有错误,但是我不想这里指定本机ip,我想指定一个固定的服务器ip,所以讲其注释掉改成:
tcpClient = new TcpClient(host,52888);host为我指定的ip
编译时候没有错误,在窗口中点击连接时,就出现异常

其实tcp编程还不是很会,希望好心人能帮我解答。

注:host是在之前定义过的一个ip地址
这个一个客户端的部分代码,源代码本来是:
//tcpClient = new TcpClient(AddressFamily.InterNetwork);//获得本机的ip地址。
运行时没有错误,但是我不想这里指定本机ip,我想指定一个固定的服务器ip,所以讲其注释掉改成:
tcpClient = new TcpClient(host,52888);host为我指定的ip
上面是你理解的有问题。
第一:tcpClient = new TcpClient(AddressFamily.InterNetwork);这句话不是获得本机的ip地址,而是要创建一个使用ip版本4的寻址方案的TcpClient对象。这时只是定义这个对象,并没有建立连接
第二:tcpClient = new TcpClient(host,52888);这句代码的意思是建立一个连接到host和其端口52888的连接,在创建时就已经连接上了。这里的host指的是你要连接的服务器IP地址。此时在创建时已经建立连接了,所以在使用BeginConnect异步调用时,抛出一个【在一个已经建立连接的套接字上做一个连接请求。

你理解上面的内容,应该就可以解决你的问题了。追问

非常感谢你对我的回答,才开始学c#确实搞不定。那原来程序是tcpClient = new TcpClient(AddressFamily.InterNetwork)这句只是定义了对象 并没有实例化,那在使用异步操作 IAsyncResult result = tcpClient.BeginConnect(IPAddress.Parse(tbxSrvIp.Text), int.Parse(tbxPort.Text), requestcallback, tcpClient);时 是如何找到ip的呢??我又想了想 我是不是应该在(IPAddress.Parse(tbxSrvIp.Text)这个参数中去得到ip地址呢??

追答

那在使用异步操作 IAsyncResult result = tcpClient.BeginConnect(IPAddress.Parse(tbxSrvIp.Text), int.Parse(tbxPort.Text), requestcallback, tcpClient);时 是如何找到ip的呢??我又想了想 我是不是应该在(IPAddress.Parse(tbxSrvIp.Text)这个参数中去得到ip地址呢??

BeginConnect方法,在此时有四个参数,第一个就是服务器的IP地址,第二个是服务器的端口。
tbxSrvIp.Text应该是是服务器IP地址,tbxProt.Text就是服务器端口。
你想得到什么ip地址?是你本机的IP地址还是服务器的IP地址?

参考技术A 你这样写呢 TcpCilent tcpClient= new TcpClient();
client.Connect("localhost",52888);不行再问。 如果想改成别的IP地址则把localhost改成对应的“127.0.0.1”格式 的IP地址,记得带双引号。追问

不知道 这样改了要出错

参考技术B ( n u l l )

C#中异步编程多个异常的处理方式

异步编程异常处理

 在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕捉异常,未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制。但是对于异步编程来说,异常处理一直是件麻烦的事情,所以接下来给大家介绍一下异步编程中的错误处理方式

单个异常的捕获

 public static async Task ThrowExcrptionAsync(int ms, string message)
        {
            await Task.Delay(ms);
            throw new Exception(message);
        }

 public static async Task Main(string[] args)
        {
            
            try
            {
               ThrowExcrptionAsync(2000, "first");
            }
            catch (Exception e)
            {
               Console.WriteLine(e.Message);
            }
            Console.ReadKey();
        }

如果调用以上的方法,并且没有等待,可以将异步方法放在try/catch中就可以捕获到异常,比如像上面一样调用ThrowExcrptionAsync方法,方法已经执行完毕,而throw new Exception(message)这句话还没执行,所以上面这段代码并不会捕获到异常

注意:返回void的异步方法不会等待,这是因为从async void方法抛出的异常无法捕获,因此,异步方法最好返回一个Task类型。处理程序方法或重写的基类方法不受此规则限制

异步方法异常的一个比较好的处理方式是使用await关键字,将其放在try/catch语句中,如以下代码琐事。异步调用ThrowExcrptionAsync方法后,主线程就会释放线程,但塔会在任务完成时保持任务的引用,此时(2s之后)会调用匹配的catch块内的代码

 public static async Task Main(string[] args)
        {
            
            try
            {
            await   ThrowExcrptionAsync(2000, "first");
            }
            catch (Exception e)
            {
               Console.WriteLine(e.Message);
            }
            Console.ReadKey();
        }

多个异常的捕获

 此时如果调用两个异步方法,每个方法都会抛出异常,我们该如何处理呢?如以下代码
 public static async Task Main(string[] args)
        {
            
            try
            {
            await   ThrowExcrptionAsync(2000, "first");
            await   ThrowExcrptionAsync(1000, "second");
            }
            catch (Exception e)
            {
               Console.WriteLine(e.Message);
            }
            Console.ReadKey();
        }

第一个ThrowExcrptionAsync被调用,2s抛出异常信息(包含信息first),该方法结束后,另一个ThrowExcrptionAsync方法也被调用,1s之后抛出异常,事实并非如此,因为第一个ThrowExcrptionAsync已经抛出了异常,try块内的代码块并没有继续调用第二个ThrowExcrptionAsync方法。而是直接进入catch块内的第一个异常进行处理,但是在现实编程中,这个并非我们所想。我们需要两个方法不管异常,都需要执行,而不是某一个报错直接跳出,所以我们使用WhenAll方法等待所有方法执行完成再catch(在外部定义两个task对象,用来接受我们要执行方法的结果),

 public static async Task Main(string[] args)
        {
            Task t1 = null;
            Task t2 = null;
            try
            {
                t1 = ThrowExcrptionAsync(2000, "first");
                t2 = ThrowExcrptionAsync(1000, "second");
                await Task.WhenAll(t1, t2);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Console.ReadKey();
        }

这个时候,我们已经让两个方法都执行了。没有管内部的错误,接下来我们去捕获两个异常中的错误信息,代码如下

public static async Task Main(string[] args)
        {
            Task t1 = null;
            Task t2 = null;
            try
            {
                t1 = ThrowExcrptionAsync(2000, "first");
                t2 = ThrowExcrptionAsync(1000, "second");
                await Task.WhenAll(t1, t2);
            }
            catch (Exception e)
            {
                if (t1.IsFaulted)
                {
                    Console.WriteLine(t1.Exception.InnerException);
                }
                if (t2.IsFaulted)
                {
                    Console.WriteLine(t2.Exception.InnerException);
                }
                Console.WriteLine(e.Message);
            }
            Console.ReadKey();
        }
在这里我们使用的的是IsFaulted属性,该属性用来检查任务的状态,以确定它们是否为出错状态,若出现异常,IsFaulted属性会返回true。可以使用Task类中的Exception.InnerException来访问信息本身。当然,我们知道IsFaulted的状态后。肯定是可以进行别的业务逻辑处理的。

另外还有一种比较快速获取task类中的异常信息的,代码如下:
public static async Task Main(string[] args)
        {
            Task taskResult = null;
            try
            {
                var t1 = ThrowExcrptionAsync(2000, "first");
                var t2 = ThrowExcrptionAsync(1000, "second");
                await (taskResult = Task.WhenAll(t1, t2));
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                foreach (var item in taskResult.Exception.InnerExceptions)
                {
                    Console.WriteLine(item.Message);
                }
            }
            Console.ReadKey();
        }
方法其实和上面的判断状态再去获取异常信息差不多,该方法主要是在日志中使用较多。

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

以上是关于c#中tcp异步编程遇到异常问题,新手感觉很不得懂 希望大神能从浅显的角度帮我解答的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中使用 httpclient 保持 TCP 端口打开

c#异步编程-Task

[C#] 走进异步编程的世界 - 剖析异步方法(下)

并发不得不说的伪共享

电脑小白学习软件开发-C#的选择语句异常捕获,进攻程序员

来自回调 c# 的未处理异常错误