文档章节

Windows Socket套接字:MFC套接字编程

LoSingSang
 LoSingSang
发布于 04/25 22:19
字数 2647
阅读 32
收藏 2

网络名词解释


同步:指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式
异步:指的是发送方不等接收方响应,便接着发下个数据包的通信方式;
阻塞:指调用某函数时,直到该函数完成操作,才返回;否则一直阻塞在该调用上
非阻塞:指调用某操作时,不管操作是否成功都立即返回,而不会挂在该操作

一.CAsyncSocket类


提供基于事件的I/O异步模型


1.create


该方法用于创建一个Windows套接字,并将其附加在CAsyncSocket类对象上
BOOL Create(UINT nSocketPort=0,int nSocketType=SOCK_STREAM,long IEvent=FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE,LPCTSTR lpszSocketAddress=NULL);
nSocketPort:套接字端口,如果为0,系统自动选择一个端口
nSocketType:套接字类型,如果为SOCK_STREAM=流式套接字,SOCK_DGRAM=数据报套接字
IEvent:套接字能够处理的网络事件
FD_READ:当套接字中有数据需要读取时触发事件
FD_WRITE:当向套接字写入数据时触发事件
FD_OOB:当接收到外带数据时触发事件
FD_ACCEPT:当接收连接请求时触发事件
FD_CONNECT:当连接完成时触发事件
FD_CLOSE:当套接字关闭时触发事件
lpszSocketAddress:套接字的IP地址


2.GetLastError


该方法用于获取最后一次操作失败的状态信息
static int GetLastError();


3.GetPeerName


该方法用于获取套接字连接中的IP地址信息
BOOL GetPeerName(CString&rPeerAddress,UINT&rPeerPort);
BOOL GetPeerName(SOCKADDR*lpSockAddr,int*lpSockAddrLen);
rPeerAddress:用于接收函数返回的IP地址
rPeerPort:用于记录端口号
lpSockAddr:一个socketaddr结构指针,用于记录套接字名称
lpSockAddrLen:用于确定lpSocketAddr的大小


4.Accept


该方法用于接受客户端的连接
virtual BOOL Accept(CAsyncSocket&rConnectedSocket,SOCKADDR*lpsockAddr=NULL,int*lpSockAddrLen=NULL);
rConnectedSocket:对应当前连接的套接字引用
lpSockAddr:一个sockaddr结构指针,用于记录套接字地址
lpSockAddrLen:用于确定lpsockaddr的大小


5.bind


该方法用于将IP地址和端口号绑定到套接字上
BOOL Bind(UINT nSocketPort,LPCTSTR lpszSocketAddress=NULL);
BOOL Bind(const SOCKADDR*lpSockAddr,int nSockAddrLen);
nSocketport:套接字端口
lpszSocketAddress:IP地址
lpSockADdr:一个sockaddr结构指针
nSockAddrLen:用于确定lpsockAddr的大小

6.connect

该方法用于发送一个连接请求
BOOL Connect(LPCTSTR lpszHostAddress,UINT nHostPort);
BOOL Connect(const SOCKADDR* lpSockAddr,int nSockAddrLen);
lpszHostAddress:主机的IP地址或网址
nHostPort:主机的端口
lpSockADdr:一个sockaddr结构指针
nSockAddrLen:用于确定lpsockAddr的大小

7.close

该方法用于关闭套接字
virtual void Close();

8.Listen

该方法用于将套接字置于监听模式
BOOL Listen(int nConnectionBacklog=5);
nConnectionBacklog:等待连接的最大队列长度

9.receive

该方法用于在流式套接字中接受数据
virtual int Receive(void* lpBuf,int nBuflen,int nFlags=0);
lpBuf:接受数据的缓冲区
nBufLen:确定缓冲区的长度
nFlags:确定函数的调用模式,MSG_PEEK=表示查看传来的数据,数据被复制到接受缓冲区,但不会从输入队列中移走;MSG_OOB=处理带外数据.

10.ReceiveFrom

该方法用于从数据包套接字中接受数据
int ReceiveFrom(void*lpBuf,int nBufLen,CString&rSocketAddress,UINT&rSocktPort,int nFlags=0);
int RecerveFrom(void *lpBuf,int nBufLen,SOCKADDR* lpSockAddr,int *lpSockAddrLen,int Flags=0);
lpBuf:接受数据的缓冲区
nBufLen:缓冲区的大小
rSocketAddress:用于接收数据报的目的地(IP地址)
rSocketPort:用于记录端口号
lpSockAddr:一个sockaddr结构指针,用于记录套接字地址信息
lpSockAddrLen:用于确定lpSockAddr的大小
nFlags:函数的调用模式

11.send


该方法用于向流式套接字中发送数据
virtual Send(const void* lpBuf,int nBufLen,int nFlags=0);
lpBuf:要发送数据的缓冲区
nBufLen:缓冲区大小
nFlags:函数调用方法

12.sendTo


该方法用于在流式套接字或数据包套接字上发送数据
int SendTo(const void*lpBuf,int nBuflen,UINT nHostPort,LPCTSTR lpszHostAddress=NULL,int nFlags=0);
int Sendto(const void*lpBuf,int nBufLen,const SOCKADDR* lpSockAddr,int nSockAddrLen,int nFlags=0);
lpBuf:要发送数据的缓冲区
nBufLen:缓冲区大小
nHostPort:主机端口号
lpszHostAddress:主机地址
lpSockAddr:一个sockaddr结构指针
nSockAddrLen:lpsockAddr的大小
nFlags:函数调用方式


13.shutDown


该方法用于在套接字上断开数据的发送或接受
BOOL ShutDown(int nHow=sends);
nHow:用于确定函数的行为,0表示不允许接收,1表示不允许发送,2表示不允许接收和发送

14.OnAccept

当套接字接收连接请求时触发该事件
virtual void OnAccept(int nErrorCode);
nErrorCode:错误代码

15.OnClose

当套接字关闭时触发该事件
virtual void OnClose(int nErrorCode);

16.OnConnect

当套接字连接后触发该事件
virtual OnConnect(int nErrorCode);

17.OnReiceive

当套接字有数据被接收时触发该事件
virtual OnReiceive(int nErrorCode);

18.Onsend

当套接字发送数据时触发该事件
virtual Onsend(int nErrorCode);

二、CSocket类


CSocket类派生于CAsyncSocket类,该类对套接字函数进行更高层次封装,并提供了同步技术。

1.create

该方法用于创建一个Windows套接字,并将其附加在CSocket类对象上
BOOL Create(UINT nSocketPort=0,int nSocketType=SOCK_STREAM ,LPCTSTR lpszSocketAddress=NULL);
nSocketPort:套接字端口,如果为0,系统自动选择一个端口
nSocketType:套接字类型,如果为SOCK_STREAM=流式套接字,SOCK_DGRAM=数据报套接字
lpszSocketAddress:套接字IP地址

2.Attach

该方法用于讲一个套接字句柄附加到CSocket类对象
BOOL Atach(SOCKET hSocket);
hSocket:套接字句柄

3.FromHandle

该方法根据套接字句柄获得CSocket对象指针
static CSocket* PASCAL FromHandle(SOCKET hSocket);
hSocket:套接字句柄
返回值:CSocket对象指针

4.lsBlocking

该方法用于判断套接字是否处于阻塞模式
BOOL lsBlocking();
返回值:0=非阻塞,非0=则塞

5.CancelBlockingCall

该方法用于取消套接字的阻塞模式
void CancelBlockingCall();

三、客户端实现过程


1.创建对话框,工程client


2.InitInstance方法中初始化套接字

 

[cpp] view plain copy

  1. BOOL CClientApp::InitInstance()  
  2. {  
  3.  WSADATA wsd; //定义WSADATA对象  
  4.  WSAStartup(MAKEWORD(2,2),&wsd); //初始化套接字  
  5. }  


 

 

3.从CSocket类派生一个子类CClientSocket,在该类中添加m_pDialog成员

 

[cpp] view plain copy

  1. CClientDlg *m_pDialog;//添加成员变量  


 

 

4.在CClientSocket中添加SetDialog方法,用于社会成员变量

[cpp] view plain copy

  1. void CClientSocket::SetDialog(CClientDlg *pDialog)  
  2. {  
  3.  m_pDialog = pDialog;//设置成员变量  
  4. }  



5.改写CClientSocket类的OnReceive方法,在套接字有数据接收时调用该方法

[cpp] view plain copy

  1. void CClientSocket::OnReceive(int nErrorCode)   
  2. {  
  3.  CSocket::OnReceive(nErrorCode);  
  4.  if (m_pDialog != NULL)//判断成员变量是否为空  
  5.   m_pDialog->ReceiveText();//调用对话框类的ReceiveText方法接收数据  
  6. }  



6.在对话框添加如下成员变量

[cpp] view plain copy

  1. CClientSocket m_SockClient;//定义套接字成员变量  
  2. CString m_Name;//定义一个字符串变量  



7.向对话框类中添加ReceiveText方法接收数据

[cpp] view plain copy

  1. void CClientDlg::ReceiveText()  
  2. {  
  3.  char buffer[BUFFERSIZE];//定义接收数据的缓冲区  
  4.  int len =  m_SockClient.Receive(buffer,BUFFERSIZE);//开始接收数据  
  5.  if (len != -1)  
  6.  {  
  7.   buffer[len] = '\0';//设置结束标记  
  8.   m_List.AddString(buffer);//向列表中添加接收到的信息  
  9.  }  
  10. }  



8.在对话框初始化时创建套接字

 

[cpp] view plain copy

  1. m_SockClient.Create();//创建套接字  
  2. m_SockClient.SetDialog(this);//设置套接字的成员变量  


9.处理“登录”按钮,开始登陆服务器

 

[cpp] view plain copy

  1. void CClientDlg::OnLogin()   
  2. {  
  3.  CString strIP,strPort;//定义两个字符串变量  
  4.  UINT port ;//定义一个整形端口变量  
  5.  m_ServerIP.GetWindowText(strIP);//获取服务器IP  
  6.  m_NickName.GetWindowText(m_Name);//获取用户昵称  
  7.  m_ServerPort.GetWindowText(strPort);//获取端口  
  8.  if (strIP.IsEmpty() || strPort.IsEmpty() || m_Name.IsEmpty())  
  9.  {  
  10.   MessageBox("请设置服务器信息","提示");  
  11.   return;  
  12.  }  
  13.  port = atoi(strPort);//将端口字符串转换为整数  
  14.  if (m_SockClient.Connect(strIP,port))//开始连接服务器  
  15.  {  
  16.   MessageBox("连接服务器成功!","提示");  
  17.   CString str;  
  18.   str.Format("%s----->%s",m_Name,"进入聊天室");  
  19.   m_SockClient.Send(str.GetBuffer(0),str.GetLength());//向服务器发送数据,再由服务器转发  
  20.  }  
  21.  else  
  22.  {  
  23.   MessageBox("连接服务器失败!","提示");  
  24.  }  
  25. }  


 


10.处理“发送”按钮,向服务器发送数据,再由服务器转发这些数据

 

 

[cpp] view plain copy

  1. void CClientDlg::OnSendText()   
  2. {  
  3.  CString strText,strInfo;//定义两个字符串变量  
  4.  m_Text.GetWindowText(strText);//获取发送的内容  
  5.  if (!strText.IsEmpty() && !m_Name.IsEmpty())  
  6.  {  
  7.   strInfo.Format("%s说: %s",m_Name,strText);//设置发送的文本  
  8. //开始发送数据  
  9.   int len = m_SockClient.Send(strInfo.GetBuffer(strInfo.GetLength()),strInfo.GetLength());  
  10.  }  
  11. }  

 

四、服务器实现过程

 

1.创建对话框,工程Server

 

2.InitInstance方法中初始化套接字

 

[cpp] view plain copy

  1. BOOL CClientApp::InitInstance()  
  2. {  
  3.   //初始化套接字  
  4.  WSADATA wsd;  
  5.  AfxSocketInit(&wsd);  
  6. }  

 


3.从CSocket类派生一个子类CServerSocket,在该类中添加m_pDlg成员

 

 

[cpp] view plain copy

  1. CServerDlg *m_pDlg;//添加成员变量  

 


4.在CServerSocket中添加SetDialog方法,用于社会成员变量

 

 

[cpp] view plain copy

  1. void CServerSocket::SetDialog(CServerDlg *pDialog)  
  2. {  
  3.  m_pDlg= pDialog;//设置成员变量  
  4. }  

 


5.改写CServerSocket类的OnAccept方法,在套接字有连接请求时接受其连接

 

 

[cpp] view plain copy

  1. void CServerSocket::OnAccept(int nErrorCode)   
  2. {  
  3.  CSocket::OnAccept(nErrorCode);  
  4.  if (m_pDlg)  
  5.   m_pDlg->AcceptConnect();  
  6. }  

 

6.从CSocket类再次派生一个新类CClientSocket,在该类中定义成员变量m_pDlg

 

[cpp] view plain copy

  1. CServerDlg* m_pDlg;  


7.向CClientSocket类中添加SetDlialog函数,为m_pDlg成员变量赋值

 

 

[cpp] view plain copy

  1. void CClientSocket::SetDialog(CServerDlg* pDialog)  
  2. {  
  3.  m_pDlg = pDialog;  
  4. }  

 


8.改写CClientSocket类的OnReceive方法,在套接字有数据时接收数据

 

[cpp] view plain copy

  1. void CClientSocket::OnReceive(int nErrorCode)   
  2. {  
  3.  CSocket::OnReceive(nErrorCode);  
  4.  if(m_pDlg)  
  5.  {  
  6.   m_pDlg->ReceiveData(*this);  
  7.  }  
  8. }  

 


9.在对话框类中添加如下成员变量

 

[cpp] view plain copy

  1. CPtrList m_socketlist;//定义套接字列表容器  
  2. CServerSocket m_ServerSock;//定义套接字  

 


10.向对话框类中添加AccceptConnect方法,接受客户端的连接

 

[cpp] view plain copy

  1. void CServerDlg::AcceptConnect()  
  2. {  
  3.  CClientSocket* psocket = new CClientSocket();//创建一个套接字  
  4.  psocket->SetDialog(this);//设置套接字成员变量  
  5.  if (m_ServerSock.Accept(*psocket))//接受套接字连接  
  6.   m_socketlist.AddTail(psocket);//将套接字添加到列表容器中  
  7.  else  
  8.   delete psocket;//连接失败,释放套接字  
  9. }  

 


11.向对话框类中添加ReceiveData方法接收数据

[cpp] view plain copy

  1. void CServerDlg::ReceiveData(CSocket &socket)  
  2. {  
  3.  char bufferdata[BUFFERSIZE];  
  4.  int len = socket.Receive(bufferdata,BUFFERSIZE);//开始接收数据  
  5.  if (len != -1)//判断是否接收到数据  
  6.  {  
  7.   bufferdata[len] = 0;//设置数据结束标记  
  8.   POSITION pos = m_socketlist.GetHeadPosition();//获取容器列表的首位置  
  9.   while (pos != NULL)//遍历容器列表  
  10.   {//获取容器列表中的指定套接字  
  11.    CClientSocket* socket = (CClientSocket*)m_socketlist.GetNext(pos);  
  12.    if (socket != NULL)//判断套接字是否为空  
  13.     socket->Send(bufferdata,len);//向套接字发送数据  
  14.   }  
  15.  }  
  16. }  



 
12.处理“设置”按钮,创建并开始监听套接字

 

[cpp] view plain copy

  1. void CServerDlg::OnConfig()   
  2. {  
  3.  m_ServerSock.SetDialog(this);//设置套接字成员变量  
  4.  CString strPort,strIP;//定义两个字符串变量  
  5.  m_ServerPort.GetWindowText(strPort);//获取端口字符串  
  6.  m_ServerIP.GetWindowText(strIP);//获取服务武IP  
  7.  if (!strPort.IsEmpty() && !strIP.IsEmpty())  
  8.  {  
  9.   UINT port = atoi(strPort);  
  10.   m_ServerSock.Create(port,SOCK_STREAM,strIP);//创建套接字  
  11.   BOOL ret = m_ServerSock.Listen();//将套接字置于监听模式  
  12.   if (ret)  
  13.    MessageBox("设置成功!","提示");  
  14.  }  
  15. }  

本文转载自:https://blog.csdn.net/greless/article/details/72763171

共有 人打赏支持
LoSingSang
粉丝 3
博文 32
码字总数 6976
作品 0
深圳
程序员
私信 提问
Visual C++网络编程案例实战

试读PDF下载: http://pan.baidu.com/s/1AEBtn 随书视频分享 http://pan.baidu.com/share/link?shareid=1501607663&uk=3593874494 随书PPT分享 http://pan.baidu.com/share/link?shareid=15......

请叫我院长
2013/11/29
747
3
Linux多线程并发服务器编程(线程池,FTP服务器)

分享网盘下载:https://pan.baidu.com/s/1gfNCcXt 密码: irfk 内容简介 本课程从最基础的进程、线程概念讲起逐步深入,通过理论与实践结合的方式,使学员快说掌握linux多线程网络编程技术,并...

人气王子333
06/26
0
0
acl 跨平台网络通信与服务器框架 3.0.21 发布

acl 3.0.21 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/FreeBsd/MacOS 平台;整个 acl 项目主要包含三...

郑树新
2014/10/31
2K
6
socket第三方库 AsyncSocket(GCDAsyncSocket)

Socket描述了一个IP、端口对。它简化了程序员的操作,知道对方的IP以及PORT就可以给对方发送消息,再由服务器端来处理发送的这些消息。所以,Socket一定包含了通信的双发,即客户端(Client)...

AmoyAI
2012/11/25
0
3
大二学生对Linux编程感兴趣,迷茫,求指点

本菜鸟已经大二,是电子信息专业的,我对linux听感兴趣,自己看了unix环境高级编程,unix网络编程卷一(socket套接字)可以自己编一个初级的聊天小程序,学了c和c++和数据结构shell脚本,专业以...

宅四年
2013/08/19
1K
12

没有更多内容

加载失败,请刷新页面

加载更多

EOS账户如何工作,我们如何获取eos账号?

EOS账户的工作方式是什么?帐户是存储在区块链中的人类可读名称。它可以由个人或一群人拥有,具体的取决于权限配置。需要一个帐户来将交易转移或推送到区块链。——EOSIO Wiki EOS账户如何工...

笔阁
4分钟前
0
0
iOS面试之@property

https://juejin.im/post/5c105c7ce51d4562d138086f @property介绍 相信做过iOS开发的同学都使用过@property,@property翻译过来是属性。在定义一个类时,常常会有多个@property,有了@proper...

壹峰
6分钟前
0
0
[springBoot系列]--springBoot注解大全

一、注解(annotations)列表 @SpringBootApplication:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。其中@ComponentScan让spring Boot扫描到Configuration类并把它加......

Jack088
20分钟前
3
0
tomcat编译超过64k大小的jsp文件报错原因

  今天遇到一个问题,首先是在tomcat中间件上跑的web项目,一个jsp文件,因为代码行数实在是太多了,更新了几个版本之后编译报错了,页面打开都是报500的错误,500的报错,知道http协议返回...

SEOwhywhy
41分钟前
5
0
flutter http 请求客户端

1、pubspec文件管理Flutter应用程序的assets(资源,如图片、package等)。 在pubspec.yaml中,通过网址“https://pub.dartlang.org/packages/http#-installing-tab-”确认版本号后,将http(0...

渣渣曦
42分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部