MFC-Socket通信

服务器界面:

大家先去 附件中 把代码下下来,否则看文章是看不懂的。服务端代码,打开类视图,找到ListenThreadFunc函数。这是我们的线程函数,socket代码在该线程里执行。

01 DWORD WINAPI
ListenThreadFunc(
LPVOID Lparam)
02 {
03     Cxads_PCServerDlg
* pServer = (Cxads_PCServerDlg *)Lparam;
04     if (INVALID_SOCKET
== (pServer->m_SockListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)))
05     {
06         AfxMessageBox(_T("建立socket失败"));
07         return 0;
08     }
09     sockaddr_in
service;
10     service.sin_family
= AF_INET;
11     service.sin_addr.s_addr
= htonl(INADDR_ANY);
12     service.sin_port
= htons(pServer->m_ServicePort);
13     if (0
!= bind(pServer->m_SockListen,(sockaddr *)&service,
sizeof(sockaddr_in)))
14     {
15         AfxMessageBox(_T("绑定端口失败"));
16         return 0;
17     }
18     if (0
!= listen(pServer->m_SockListen,5))
19     {
20         AfxMessageBox(_T("监听端口失败"));
21         return 0;
22     }
23  
24     //提示建立socket成功
25     pServer->EnableWindow(IDC_BUTTONEND,TRUE);
26 // 
pServer->EnableWindow(IDC_BUTTONSEND,TRUE);
27     pServer->EnableWindow(IDC_BUTTONSTART,FALSE);
28     pServer->SetRevBoxText(_T("服务启动成功,开始监听端口"));
29     //进入循环,监听端口
30     while (TRUE)
31     {
32         if (socket_Select(pServer->m_SockListen,100,TRUE))
33         {
34             sockaddr_in
clientAddr;
35             int iLen
sizeof(sockaddr_in);
36             SOCKET
accSock = accept(pServer->m_SockListen,(
struct sockaddr
*)&clientAddr,&iLen);
37             if (accSock
== INVALID_SOCKET)
38             {
39                 continue;
40             }
41             //将节点加入链中
42             CClientItem
tItem;
43             tItem.m_ClientSocket
= accSock;
44             tItem.m_strIp
= inet_ntoa(clientAddr.sin_addr); 
//IP地址
45             tItem.m_pMainWnd
= pServer;
46             int idx
= pServer->m_ClientArray.Add(tItem); 
//idx是第x个连接的客户端
47             tItem.m_hThread
= CreateThread(NULL,0,ClientThreadProc, 
//创建一个线程并挂起:CREATE_SUSPENDED
48                 &(pServer->m_ClientArray.GetAt(idx)),CREATE_SUSPENDED,NULL);
49             pServer->m_ClientArray.GetAt(idx).m_hThread
= tItem.m_hThread;
50             //等把hThread加入了节点,才开始执行线程,如下
51             ResumeThread(tItem.m_hThread);
52             pServer->SetRevBoxText(tItem.m_strIp
+ _T(
"上线"));
53             Sleep(100);
54         }
55     }
56 }

Cxads_PCServerDlg是我们对话框程序的类,我们传进来的参数就是这个类对象。pServer指向该对象。

1.pServer->m_SockListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))

socket函数初始化一个socket。socket是什么?socket相当于通信的一个管道,m_SockListen是一个监听的socket。我们一会就要监听这根"管道",看是否有客户端连接。socket()中的参数像我这样写,代表这是个TCP连接。TCP连接和UDP连接的区别就是,TCP是要双方建立连接后才能通信,就想打电话;而UDP是单方面就能发送信息,就想发短信。

2.bind(pServer->m_SockListen,(sockaddr *)&service,sizeof(sockaddr_in))

bind函数是绑定一个端口和IP地址。第一个参数是刚才新建的监听socket,第二个参数是一个sockaddr_in结构体,里面保存着IP地址和端口。因为我们这是服务端,所以保存的IP地址和端口是自己的,htonl(INADDR_ANY)就是将IP地址绑定为任意,这样你的IP可以是127.0.0.1,也可以是192.168.x.x,也可以是你的外网IP。htons(pServer->m_ServicePort)是要监听的IP,我这里是从输入框获取的,你也可以使用固定的比如htons(8260)。

  3.listen(pServer->m_SockListen,5)

开始监听了。5代表等待连接队伍的最大长度,一般都是5就行。

4.

进入while循环,大家可以看到这是个死循环。while(TRUE)永远不会退出去。while中间只有个if语句,socket_Select(pServer->m_SockListen,100,TRUE)是一个select选择模型,作用是向socket中看一眼,如果有信息则返回TRUE,如果没有信息则返回FALSE。有信息代表有客户端来连接了,于是我们进入if语句。

5.SOCKET accSock = accept(pServer->m_SockListen,(struct sockaddr *)&clientAddr,&iLen);

大家可以看到我又建了一个socket,不是刚才那个了。accept函数就返回一个socket,这个socket就是和该客户端通信的"管道"。传入的参数和bind类似,只是第二个变成得到客户端的IP与端口了。

6.

之后有一个将节点加入链表的过程。因为我们连接服务端的客户端不止一个,所以我们要将每一个客户端的IP、SOCKET和相关信息加入链表,以供以后使用。而且大家可以看到,我们这个while里面又新开了一个线程,这个线程的作用就是和该客户端通信。

7.

休息100毫秒后while循环继续执行,等待下一个客户端连接。



这就是服务端socket的代码,通信的部分我客户端里介绍,服务端和客户端基本是一样的,大家可以自己看代码比较。

打开客户端,找到ConnectSocket方法,这是我们从socket中获取信息的一个方法。

01 BOOL Cxads_PCClientDlg::ConnectSocket(Cxads_PCClientDlg
* pClient)
02 {
03     m_ClientSock
= socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
04     if (NULL
== m_ClientSock)
05     {
06         MessageBox(_T("创建socket失败"));
07         return FALSE;
08     }
09     sockaddr_in
sa;
10     sa.sin_family
= AF_INET;
11     CString
strIp;
12     DWORD dPort
= GetDlgItemInt(IDC_EDITPORT);
13     GetDlgItemText(IDC_IPADDRESS,strIp);
14     if (strIp
== _T(
"0.0.0.0")
|| (dPort >= 65535 && dPort < 1024) || dPort == 0)
15     {
16         MessageBox(_T("请输入正确IP地址或端口"));
17         return FALSE;
18     }
19     sa.sin_port
= htons(dPort);
20     char szIpAdd[32];
21     USES_CONVERSION; //定义后才能使用T2A
22     sprintf_s(szIpAdd,32,"%s",T2A(strIp));
23     sa.sin_addr.S_un.S_addr
= inet_addr(szIpAdd);
24     if (SOCKET_ERROR
== connect(m_ClientSock,(sockaddr *)&sa,
sizeof(sa)))
25     {
26         MessageBox(_T("连接客户端错误,请检查你填写的IP和端口是否错误"));
27         return FALSE;
28     }
29  
30     pClient->SetRevBoxText(_T("连接服务器成功"));
31     pClient->EnableWindow(IDC_BUTTONSTOP,TRUE);
32     pClient->EnableWindow(IDC_BUTTONCONNECT,FALSE);
33     isServerOn
= TRUE;
34     OnEnChangeEditsendbox();
35  
36     CString
strMsg;
37     while (TRUE)
38     {
39         if (socket_Select(m_ClientSock,100,TRUE))
40         {
41             char szMsg[MAX_BUFF]
= {0};
42             int iRead
= recv(m_ClientSock,szMsg,MAX_BUFF,0);
43             if (iRead
> 0)
44             {
45                 strMsg
= szMsg;
46                 pClient->SetRevBoxText(strIp
+ _T(
">>")
+ strMsg);
47             }
48             else
49             {
50                 pClient->SetRevBoxText(_T("已断线,请重新连接"));
51                 isServerOn
= FALSE;
52                 return TRUE;
53             }
54         }
55     }
56     return TRUE;
57 }

  1.

同服务端一样,调用socket()初始化socket.

2.connect(m_ClientSock,(sockaddr *)&sa,sizeof(sa))

连接服务端。和服务端的accept函数类似,第二个参数传入sockaddr_in结构体,里面保存着服务端的IP地址和端口。如果连接成功,则返回0。

 3.

进入一个while循环。这个while虽然也是while(TRUE),但不是一个死循环,中间有break可以使while循环退出。while中仍然用到socket_Select()函数,作用也是向socket中看一眼,如果有信息则返回T,否则返回F。有信息代表从服务端发送来了内容。

 4.int iRead = recv(m_ClientSock,szMsg,MAX_BUFF,0);

recv()函数接受信息,第一个参数传入socket,第二个参数传入接受的信息保存的字符串数组,第三个传入数组长度,第四个填0即可。返回值是接受信息的字节数,如果=0说明对方不在线了。



这个方法告一段落。有人问了,那怎么发送信息呢?别急,在类视图中找到OnBnClickedButtonsend()方法。

01 void Cxads_PCClientDlg::OnBnClickedButtonsend()
02 {
03     //
TODO: 在此添加控件通知处理程序代码
04     USES_CONVERSION;
05     char szBuf[256]
= {0};
06     CString
strGetMsg;
07     int iWrite;
08     GetDlgItemText(IDC_EDITSENDBOX,strGetMsg);
09     strcpy_s(szBuf,T2A(strGetMsg));
10     iWrite
= send(m_ClientSock,szBuf,256,0);
11     if(SOCKET_ERROR
== iWrite){
12         SetRevBoxText(_T("发送错误"));
13     }
14     SetRevBoxText(_T("我自己
>>"
)
+ strGetMsg);
15     SetDlgItemText(IDC_EDITSENDBOX,_T(""));
16     return;
17 }

这是点击了发送按钮执行的代码。只有一个点,就是send()函数。

iWrite = send(m_ClientSock,szBuf,256,0);

与recv类似,发送保存在szBuf中的内容到m_ClientSock。

时间: 2024-11-06 13:13:50

MFC-Socket通信的相关文章

iOS:socket通信

ios开发 Socket通信 Socket描述了一个IP.端口对.它简化了程序员的操作,知道对方的IP以及PORT就可以给对方发送消息,再由服务器端来处理发送的这些消息.所以,Socket一定包含了通信的双发,即客户端(Client)与服务端(server). 1)服务端利用Socket监听端口: 2)客户端发起连接: 3)服务端返回信息,建立连接,开始通信: 4)客户端,服务端断开连接. 1套接字(socket)概念 套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操

关于socket通信的杂谈

用MFC写了个跟打印机相关的小应用 由于需要接受网络服务端传来的数据 所以就用到了socket通信 socket 创建 连接 发送 接收 关闭 其他都还好 只是接收数据的时候 会出现乱码 出现的情况是 当有中文字符出现的时候就会出现,这是因为每个中文字符占两个字节 所以接收数据的时候要一个字节一个字节的接收,或者一位一位的接收(Byte) 有的同学传递 图片 文件的时候也是会出现乱码的,这个也是其中原因之一. 一般也是主要原因吧. 如果要保证传输和接收的字符的编码格式一样.这个问题找了好久 .

TCP及socket通信原理

一.网络互联模型 因特网在刚面世时,只有同一制造商生产的计算机才能彼此通信,制定网络互联模型的目的就是为异种的计算机互连提供一个共同的基础和标准框架,并为保持相关标准的一致性和兼容性提供共同的参考. 互联参考模型: OSI七层模型(Open System Interconnect):应用层.表示层.会话层.传输层.网络层.数据链路层.物理层 DoD四层模型:是OSI七层模型的浓缩版,包括 进程/应用层.主机到主机层.因特网层.网络接入层 以上两种模型是层次型的,分层模型的优点主要在于: ①将网络

java socket通信-传输文件图片--传输图片

ClientTcpSend.java   客户端发送类 package com.yjf.test; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.net.InetSocketAddress; import java.net.Socket; public class ClientTcpSend { public static String clien

c# socket通信较完善方案

c#的socket通信应用.文件较多.附件为工程.  core AbstractBytesWorker.cs    字节工作器(基类),用于用于同一不同功能的字节工作器 BinaryHand.cs  2进制处理器.  ThDispose.cs 处理回收相关 crc  entity ThPersonInfo.cs manager ThSocketManager.cs  ThSocketManagerBusiness.cs 所有的业务 request RequestCode.cs  请求码 ThPr

深入浅出讲解:php的socket通信

深入浅出讲解:php的socket通信 对TCP/IP.UDP.Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵.那么我想问: 1.         什么是TCP/IP.UDP?2.         Socket在哪里呢?3.         Socket是什么呢?4.         你会使用它们吗? 什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协

Android简单Socket通信demo

一.Android Socket 通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据.而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求. 那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通信的端口,即端口通信

php的socket通信

对TCP/IP.UDP.Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵.那么我想问: 1.         什么是TCP/IP.UDP?2.         Socket在哪里呢?3.         Socket是什么呢?4.         你会使用它们吗? 什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网

Socket通信(转)

一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据.而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求. 那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通信的端口,即端口通信.通过建立sock

基于Java NIO的Socket通信

Java NIO模式的Socket通信,是一种同步非阻塞IO设计模式,它为Reactor模式实现提供了基础. 下面看看,Java实现的一个服务端和客户端通信的例子. NIO模式的基本原理描述如下: 服务端打开一个通道(ServerSocketChannel),并向通道中注册一个选择器(Selector),这个选择器是与一些感兴趣的操作的标识(SelectionKey,即通过这个标识可以定位到具体的操作,从而进行响应的处理)相关联的,然后基于选择器(Selector)轮询通道(ServerSock