AsyncSocket
- 格式:doc
- 大小:104.50 KB
- 文档页数:4
MFC中CAsyncSocket及其派生类对象跨线程使用方法存在的现象在MFC中用多线程方法开发WinSocket通讯程序时,如果你的的是API方式,自然没有以下说的问题。
但如果当你使用CAsyncSocket 及其派生类(CSocket或是你自己的写的)来开发的话,会发现在不同线程中使用CAsyncSocket及其派生类对象时,会出现程序崩溃。
这里所说的跨线程,是指该对象在一个线程中调用Create/Close/Attach/Detach函数,然后在另外一个线程中调用其他成员函数如Receive/ReceiveFrom/Send /SendTo等。
下面是一个典型的导致崩溃的例子程序(片断):CAsyncSocket async_socket;UINT ThreadProc(LPVOID) //出错:1{TRACE("======== ThreadDeattch出错:1 ========\n");async_socket.Close (); //错误发生在这个调用上:要进行关闭async_socket对象.return 0;}void CTsAsncSocketDlg::OnBnClickedButtonCreate() //出错:1{async_socket.Create(0);//async_socket对象在主线程中被建立::AfxBeginThread(ThreadProc,0,0,0,0,0); //async_socket对象在主线程中被传递到另外的线程:ThreadProc}要想知道错误的原因,可以跟进去分析。
这样说起来又太繁琐了,网上有不少类似的文章,问题的关键是不要在不同线程中进行Create/Close调用。
首先,当你的程序有问题的时候,怎样来判断是因为这个问题?这是关键一步。
调试/断点/观测等有很多手段,VC++的IDE在个这个方面是非常出色的。
这里还有个简单的方法。
linux async 异步用法
在Linux中,异步(asynchronous)操作是一种非阻塞的操作方式,可以在执行一个操作时继续执行其他任务,而不需要等待该操作完成。
这种方式可以提高程序的响应速度和并发性。
在Linux中,通常使用以下方法实现异步操作:
1. 使用非阻塞I/O:通过将文件描述符设置为非阻塞模式,可以在读写文件时立即返回,而不是等待数据准备好或者写入完成。
可以使用`fcntl()`函数将文件描述符设置为非阻塞模式,或者使用`O_NONBLOCK`标志在调用`open()`函数时指定。
2. 使用信号(signal):通过注册信号处理函数,可以在某个事件发生时,立即响应该事件而不需要等待。
可以使用`signal()`函数注册信号处理函数,当指定的信号发生时,执行注册的处理函数。
3. 使用回调函数(callback):在执行某个操作时,可以指定一个回调函数,当该操作完成时,系统会调用该回调函数。
可以通过函数指针或者函数对象来指定回调函数。
4. 使用多线程或者多进程:可以将耗时的操作放在单独的线程或进程中执行,以避免阻塞主线程或进程的执行。
在多线程或者多进程中,可以使用线程或进程间的同步机制(如锁、条件变量、信号量等)来协调不同线程或进程之间的操作。
5. 使用事件驱动库:可以使用一些基于事件驱动的库,如libevent、libuv 等,来实现异步操作。
这些库提供了一套异步操作的接口和事件循环机制,开发者可以通过注册回调函数处理特定事件。
译文:异步Socket服务器与客户端(An Asynchronous Socket Server and Client)Socket组件与框架评论(原创翻译文章·转载请注明来源:/hulihui)∙原文:An Asynchronous Socket Server and Client.by Andre Azevedo∙Download source code - 195.1 KB目录∙前言∙Socket连接(Socket Connection)∙Socket服务(Socket Service)∙连接主机(Connection Host)o加密与压缩(Encrypt与Compress)o请求入队(Enqueuing Requests)o确保发送和接收(Ensure send and recieve)o检查消息头(Check message header)o检查空闲连接(Checking idle connections)∙加密服务o SSL认证(SSL authentication)o对称认证(Symmetric authentication)∙连接创建者(Connection Creator)∙Socket服务器与Socket侦听者(SocketServer and SocketListener)o Socket服务器构造函数与方法(SocketServer constructor and methods)∙Socket客户端与Socket连接者(SocketClient and SocketConnector)o Socket客户端构造函数与方法(SocketClient constructor and methods)∙应答演示项目(Echo Demo Project)o主机(Hosts)o服务(Services)∙结语(Conclusion)∙版本历史(History)前言[H]、 [0]、[1]、[2]、 [3]、[4]、[5]、 [6]、[7]、[8]、 [9]、[10]2000年以来,我一直使用Delphi5.0和一些第三方库(Synapse )做Socket 相关的工作。
Socket调⽤⽅式(同步,异步,阻塞,⾮阻塞)同步:我调⽤⼀个功能,该功能没有结束前,我死等结果。
异步:当⼀个异步过程调⽤发出后,调⽤者不能⽴刻得到结果。
该功能在完成后,通过状态、通知和回调来通知调⽤者。
同步和⾮同步关注的是调⽤者是否等待等待调⽤结果。
举个通俗的例⼦:你打电话问书店⽼板有没有《分布式系统》这本书,如果是同步通信机制,书店⽼板会说,你稍等,”我查⼀下",然后开始查啊查,等查好了(可能是5秒,也可能是⼀天)告诉你结果(返回结果)。
⽽异步通信机制,书店⽼板直接告诉你我查⼀下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。
然后查好了,他会主动打电话给你。
在这⾥⽼板通过“回电”这种⽅式来回调。
阻塞:调⽤我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。
⾮阻塞:调⽤我(函数),我(函数)⽴即返回通知调⽤者以最常⽤的send和recv两个函数为例⽐如你调⽤send函数发送⼀定的Byte,在系统内部send做的⼯作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执⾏成功并不代表数据已经成功的发送出去了,如果TCP/IP协议栈没有⾜够的可⽤缓冲区来保存你Copy过来的数据的话...这时候就体现出阻塞和⾮阻塞的不同之处了:对于阻塞模式的socket send函数将不返回直到系统缓冲区有⾜够的空间把你要发送的数据Copy过去以后才返回,⽽对于⾮阻塞的socket来说send会⽴即返回WSAEWOULDDBLOCK告诉调⽤者说:"发送操作被阻塞了!!!你想办法处理吧..."对于recv函数,同样道理,对于阻塞模式的socket来说如果TCP/IP协议栈的接收缓冲区没有通知⼀个结果给它它就⼀直不返回:耗费着系统资源....对于⾮阻塞模式的socket该函数会马上返回,然后告诉你:WSAEWOULDDBLOCK---"现在没有数据,回头再来看看"阻塞I/O模型:⾮阻塞I/O模型:阻塞和⾮阻塞关注的是调⽤者在等待调⽤结果时的状态。
SocketAsyncEventArgs使⽤解说如果在.NET下写过⽹络通讯的同学应该感觉不陌⽣了,有很多刚⼊门的同学很多都认为这东西可以⼤⼤提⾼处理效能还有就是使⽤上很不适应.其实使⽤之前最好通过MSDN了解⼀下,该对象紧紧是Begin End模式的⼀个增强版本,它的主要作⽤主要是解决之前异步过程时创建不可复⽤的异步对象⽽产⽣的.主要是在⾼并发下节省⼤量对象重分配和同步相关问题,从⽽实现在⾼并发吞吐下更少的资源损耗(如果你的应⽤紧紧是密集通讯那性能提供相对来说是可观⼀点,但应⽤还存在其他处理那就不要想着它能有质的改变了).SocketAsyncEventArgs(SAEA)在.net 2.0 sp1所提供开发⼈员主要使⽤它的场景分别是Accept,Send和Receive.在传统的Begin End模式中⼀般都通过调⽤Begin⽅法然后在回调⽅法中调⽤End来处理,其实SAEA原理差不多,只是由原来的指定的回调过程变成了完成事件,更重要的⼀个改变就是SAEA是可以复⽤的.下⾯详解⼀下SAEA的以上⼏种⽤法.主要属性和事件在使⽤SocketAsyncEventArgs进⾏TCP或UDP通讯的时候最常⽤的⼏个成员分别是:Buffer,BufferList,BytesTransferred,SocketError,UserToken,BytesTransferred属性,SetBuffer⽅法和Completed事件。
SocketAsyncEventArgs接收和发送数据都需要设置buffer,⼀般⽤SetBuffer⽅法或设置BufferList。
通过Completed来查看完成情况,⽽在Completed通过SocketError和BytesTransferred结合来判断当前操作是否成功能,如在receive状态当BytesTransferred为零的时候,说明对⽅已经把连接断开了。
由于SocketAsyncEventArgs是异步操作,在很多情况需要的⼀些其他信息传递到Completed事件中,这个时候可以通过UserToken属性来解决异步信息传递的问题。
调用async方法Async方法是一种在异步编程中常用的构建模块。
这种模块可以使得在JavaScript中执行异步操作更加容易和直观。
在Web开发中,异步操作是不可避免的,因为前端页面中的事件处理和网络请求都是需要和服务器端进行通信和交互的。
使用异步编程的优势在于可以提高页面的性能和用户体验。
调用Async方法的步骤如下:1、定义一个Async任务对象。
这个任务对象可以包含多个任务,每个任务都是一个async函数。
2、使用await运算符调用async函数执行任务。
当任务执行完毕后,会返回一个Promise对象,可以使用then方法来处理异步的返回结果。
3、在处理异步返回结果的时候,可以使用try-catch语句来捕获异步操作的异常情况,以便更好地处理这些异常情况。
举个例子,假设我们有一个Web应用程序,需要获取用户信息并更新页面上的用户信息。
我们可以使用async方法来实现这个功能:async function updateUserProfile(userId) {try {const userInfo = await getUserInfoFromServer(userId);updateUserInfoInPage(userInfo);} catch {handleNetworkError();}}在这个例子中,我们使用async函数getUserInfoFromServer来请求服务器端的用户信息,并使用await来等待异步请求的返回结果。
如果请求成功,就使用updateUserInfoInPage方法来更新页面上的用户信息。
如果发生异常错误,就调用handleNetworkError方法来处理这种异常情况。
总之,调用Async方法是一种简单、可靠且方便的处理异步操作的方式。
异步操作已经成为了现代Web开发中不可或缺的一部分,因此在开发中合理使用Async方法可以提高代码的可读性和可维护性,并让Web应用程序更加稳定和高效。
(原创实用版4篇)编制人员:_______________审核人员:_______________审批人员:_______________编制单位:_______________编制时间:____年___月___日序言下面是本店铺为大家精心编写的4篇《socket的receive方法》,供大家借鉴与参考。
下载后,可根据实际需要进行调整和使用,希望能够帮助到大家,谢射!(4篇)《socket的receive方法》篇1Socket 的接收方法主要包括以下几种:1. synchronous receive 方法:阻塞方法,等待客户端发送数据后才进行接收,适用于数据量较小且传输速度较慢的情况。
使用方法为:socket.receive(byte[] buffer, int length, SocketTimeout timeout);2. asynchronous receive 方法:异步方法,可以不等待客户端发送数据就进行接收,适用于数据量较大或传输速度较快的情况。
使用方法为:socket.begin_receive(byte[] buffer, int length, SocketAsyncEventHandler callback);3. overlapped receive 方法:重叠方法,可以在多个操作之间重叠执行,提高性能,但需要支持 Windows API。
使用方法为:socket.overlapped_receive(byte[] buffer, int length, SocketOverlappedEventHandler callback);其中,synchronous receive 方法和 asynchronous receive 方法都可以使用 select 或 poll 方法实现阻塞或非阻塞接收,而 overlapped receive 方法则需要在 Windows 系统上使用。
SocketGCDAsyncSocket(异步Socket)Socket*********************************************简单理解Socket 就是⽹络连接,可以实现两个点之间的数据通讯。
•Socket允许使⽤长连接,允许应⽤程序运⾏在异步模式(提⾼效率),只有在需要的时候才接收数据•使⽤Socket,可以只传送数据本⾝⽽不⽤进⾏XML封装,⼤⼤降低数据传输的开销在(JSON)之前出现的iOS中常⽤的两种Socket类型Ø流式Socket(SOCK_STREAM):流式是⼀种⾯向连接的Socket,针对于⾯向连接的TCP服务应⽤Ø数据报式Socket(SOCK_DGRAM):数据报式Socket是⼀种⽆连接的Socket,对应于⽆连接的UDP服务应⽤•在iOS中以NSStream(流)来发送和接收数据开发步骤{⽹络连接设置 1.设置⽹络连接,绑定到主机和端⼝ 2.设置输⼊流和输出流的代理,监听数据流的状态 3.将输⼊输出流添加⾄运⾏循环 4.打开输⼊流和输出流发送消息给服务器有可读取字节时,读取服务器返回的内容到达流末尾时,关闭流,同时并从主运⾏循环中删除}通过Scoket可以实现所有的⽹络功能:包括:GET、POST、PUT、DELETE⽂件读取、写⼊(I/O)⽅式是以(⼆进制)流的⽅式读取的最主要的应⽤场景是:⾃定义的协议,编写⾃由的⽹络应⽤!Socket 的难点:1. 因为所有的(I/O)输⼊输出都是在⼀个代理⽅法中调⽤,随着⾃定义协议的复杂度的提⾼,程序编写难度势必要⼤幅度提升。
2. 多线程的处理!输⼊流和输出流都添加到了主运⾏循环,如果应⽤过于复杂,将影响主线程程序的性能因此,需要使⽤另外⼀个运⾏循环,专门管理输⼊输出流。
代理⽅法的⼯作是对数据的输⼊输出流进⾏“解析”,解析⼯作同样不需要影响到主线程的⼯作。
3.多线程⽅⾯的处理,是Socket的⼀⼤难点!可以使⽤第三⽅框架GCDAsyncSocket来解决多线程问题。
CAsyncSocket聊天程序
一、需求分析
如图1和图2,分别设计服务器端程序和客户端程序,单击客户端的“access server”按钮,可以连接到服务器端,单击客户端的“sendto”按钮,可以将编辑框中的文字发送的服务器端,并在服务器端对话框中的编辑框中显示,单击服务器端“Send”按钮,可以将服务器端对话框中的编辑框的内容发送到客户机端并显示在编辑框中。
通过此实验,验证基于CasyncSocket类建立服务器与客户机通信的实现机制。
体验消息机制的优势。
图1、服务器端程序界面图2、客户机端程序界面
二、程序设计步骤
1、服务器端程序
(1)创建基于“基本对话框”的项目AsyncSer,注意选中“包含WOSA支持”;
(2)在对话框中删除“TODO:在这里设置对话框”文字提示,为对话框添加编辑框和命令按钮,为编辑框绑定control类型的变量m_edit,将命令按钮改名为“Send”;
(3)切换到类视图,为项目添加基于CasyncSocket类的新类,此步的目的是为了重载CasyncSocket类中的OnReceive()等函数,以实现根据消息来自动触发相关函数,实现数
据在服务器与客户机之间的传送与接收。
具体做法是:右击项目名称“AsyncSer classes”,在弹出的快捷菜单中单击“New Class。
”
菜单项(图3),出现图4,选择所要新建类的类型为“MFC Class”,Name为CServerSocket,Base Class 为CAsyncSocket,即以CasyncSocket类为基类,派生新类CserverSocket(注意类名的大小写)。
图3、添加新类快捷菜单图4 “新建类”对话框
按同样的方法,为项目再添加一个以CAsyncSocket类为基类的新类CClientSocket。
说明:创建CServerSocket类的目的为了创建用来侦听的套接字,而创建CClientSocket类的目的为了创建用来和客户机连接并通信的套接字。
因为侦听套接字的主要作用在于侦听,只需重载OnConnect函数即可,而连接套接字的主要功能在于数据的传送和接收,通常要重载OnReceive函数,所以习惯上要将侦听套接字和连接套接字分别由不同类来创建。
下面重载有关的函数:
对CServerSocket类,重载其OnAccept函数。
按“Ctrl+W”键,弹出MFC ClassWizard 窗
(消息映射)选项卡,在Class Name:下拉列表框中选择CServerSocket,口(图5),选中“Message Maps”
可以看到,在Messages列表栏中列出了一些消息响应函数,这些函数都是基类CAsyncSocket类的消息响应函数,双击其中的:OnAccept,即可实现在CServerSocket类中重载CAsyncSocket类的OnAccept函数,注意,此时OnAccept函数还没有添加功能,我们将在下面的步骤中添加。
同样的方法,为CClientSocket类重载函数OnReceive函数。
当然,其功能也在下面的步骤中添加。
图5 MFC ClassWizard 窗口
(4)为对话框类添加变量:先在类视图中右击对话框类CAsyncSerDlg,在弹出的快捷菜单中选择Add MemberV ariable,添加侦听套接字server,其类型为CServerSocket,添加连接套接字client,其类型为CClientSocket。
添加字符数组buff[200],类型为char,用来存储接收或发送的数据。
(5)重载CServerSocket::OnAccept(int nErrorCode)函数。
OnAccept函数在收到客户端程序的连接请求时会自动调用,此函数的调用意味着服务器已经收到客户端的连接请求,应该在此函数中应创建与客户端的连接,代码如下:
void CServerSocket::OnAccept(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
CAsyncSerDlg * dlg=(CAsyncSerDlg*)AfxGetApp()->GetMainWnd();
//上面代码的含义大家要想明白
Accept(dlg->client); //让client套接字与客户机建立连接,server套接字继续侦听。
CAsyncSocket::OnAccept(nErrorCode);
}
因为CServerSocket:类用到了
CAsyncSerDlg * dlg=(CAsyncSerDlg*)AfxGetApp()->GetMainWnd();,故应在CServerSocket:类中添加语句#include “asyncserdlg.h”,CClientSocket类也是如此。
(6)重载CClientSocket类的OnReceive函数。
OnReceive函数在数据发送到后自动调用,此函数主要作用是接收数据。
代码如下:
void CClientSocket::OnReceive(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
CAsyncSerDlg * dlg=(CAsyncSerDlg*)AfxGetApp()->GetMainWnd();
Receive(dlg->buff,200,0);
dlg->m_edit.SetWindowText(dlg->buff);
CAsyncSocket::OnReceive(nErrorCode);
}
(7)为Send按钮定义函数:在资源视图中打开对话框,双击Send按钮,自动切换到代码编辑界面,输入以下代码
m_edit.GetWindowText(buff,200);
client.Send(buff,200,0);
在OnInitDialoge函数中,添加代码:
server.Create(3000);
server.Listen();
服务器端程序设计完成。
2、客户端程序设计
(1)创建基于“基本对话框”的项目AsyncClient,注意选中“包含WOSA支持”;
(2)在对话框中删除“TODO:在这里设置对话框”文字提示,为对话框添加编辑框和2个命令按钮,为编辑框绑定control类型的变量m_edit,将命令按钮1改名为“Access Server”,命令按钮2改名为“Send to”;
(3)为项目添加类CMySocket,派生自CAsyncSocket类,并重载OnReceive函数,以便有数据发过来时,接收数据并显示到对话框中的编辑框中,代码如下:
void CMySocket:: OnReceive (int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
CAsyncClientDlg *dlg=(CAsyncClientDlg *)AfxGetApp()->GetMainWnd();
Receive(dlg->buff,200,0);
dlg->m_edit.SetWindowText(dlg->buff);
CAsyncSocket::OnReceive(nErrorCode);
}
在CMySocket类中也要有#include “asyncClient.h”,不然CAsyncClientDlg *dlg=(CAsyncClientDlg *)AfxGetApp()->GetMainWnd();将在编译时出错。
(4)为对话框类CA yncClientDlg添加CMySocket类的对象client,用来与服务器建立连接。
Char 类数据buff[200],用来存放收发的数据。
在OnInitDialog()函数中添加client.Create();
(5)为Access Server命令按钮创建函数,一般单击它时实现与服务器的连接,代码如下:
CString errcode;
if(client.Connect("127.0.0.1",3000))
m_edit.SetWindowText("连接成功");
else
{
errcode.Format("%d",GetLastError());
m_edit.SetWindowText(errcode);
}
为Sendto按钮创建函数,以实现单击此按钮时,将编辑框中的数据发送到服务器。
代码如下:m_edit.GetWindowText(buff,200);
CString kk;
kk.Format("%d",client.Send(buff,200,0));
m_edit.SetWindowText(kk);。