【网络通信】Wince 和 PC 通过USB 用Socket 进行通信

2023-05-16

网上资料比较少或者说讲的不太详细,现在进行总结下,刚毕业没接触过WINce,不过和MFC差不多,现在进入正题



刚开始我的疑惑是Wince是如何和PC进行通信的,以及能在USB模式下进行socket通信,后来知道,当你将(要安装Windows Mobile 设备中心)USB把Wince和PC相连接的时候,我在想WInce的IP如何和PC的IP在一个网段,要知道connect socket要在一个网段的,后来知道Wince用USB连接后(我猜是有虚拟网卡)会给WINce默认一个192.168.55.101的IP, 255.255.255.0的子网掩码,以及192.168.55.100的网关(你可以在连接USB后用wince的command和ipconfig下),然后网上查找会给电脑一个192.168.55.100的IP,我在想那么多Wince,而我的需求是不能再界面上配置IP,那么多wince设备连接,IP是如何分配的。我需要在程序里写死,后来知道Wince的IP是固定的,这样就简单了。


好知道了IP和原理接下去是如何进行通信了,你会说,和还不一样,和MFC的Socket一样呗。我开始也是这么理解的,网上资料又少,绕了很多路,在Wince和PC用USB通信的情况下,Wince只能做客户端,PC只能做服务端(我反过来试了下没能成功),谷歌上写的也是如此,这样害我的工作一下子变麻烦了。


========================

下面先贴出Wince客户端的代码:

WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	fd_set fdRead;
	timeval TimeOut;
	TimeOut.tv_sec=0;
	TimeOut.tv_usec=500;

	int nNetTimeout = 500;

	wVersionRequested = MAKEWORD( 1, 1 );

	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		return 0;
	}
	//WinSock DLL 版本是否低于1.1

	if ( LOBYTE( wsaData.wVersion ) != 1 ||
		HIBYTE( wsaData.wVersion ) != 1 ) {
			WSACleanup( );
			return 0; 
	}


	SOCKET sockClient;
	int		nRet = 0;
	DWORD	dwErr = 0;
	byte	msg[1024];
	byte	recvData[255];

	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr=inet_addr("192.168.55.100");
	addrSrv.sin_family=AF_INET;
	addrSrv.sin_port=htons(26023);

	sockClient=socket(AF_INET,SOCK_STREAM,0);

	while(true)
	{
		if(WAIT_OBJECT_0 == WaitForSingleObject(pDlg->m_hReadHandle, 500))
		{
			SetEvent(pDlg->m_hExitReadHandle);
			break;
		}
		
		//向服务器发出连接请求
		nRet = connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
		if(SOCKET_ERROR == nRet)
		{
			//pDlg->GetDlgItem(IDC_STATIC_MSG)->SetWindowText(_T("USB连接失败,请检查数据线!"));
			//dwErr = WSAGetLastError();
			Sleep(1000);
			continue;
		}

		int nLen = 0;
		ZeroMemory(&msg, sizeof(msg));
		pDlg->GetDlgItem(IDC_STATIC_MSG)->SetWindowText(_T("USB已连接。"));

		while(true)
		{
			if(WAIT_OBJECT_0 == WaitForSingleObject(pDlg->m_hReadHandle, 500))
			{
				SetEvent(pDlg->m_hExitReadHandle);
				goto END;		
			}
			int nRecvLen = 0;
			ZeroMemory(&recvData, sizeof(recvData));

// 			FD_ZERO(&fdRead);
// 			FD_SET(sockClient,&fdRead);
// 			int ret=::select(0,&fdRead,NULL,NULL,&TimeOut);
// 			if (ret == 0)
// 			{
// 				closesocket(sockClient);
// 				sockClient=socket(AF_INET,SOCK_STREAM,0);	
// 				break;
// 
// 			}

			int backcon = setsockopt(sockClient,SOL_SOCKET, SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int)); 

			nRecvLen = recv(sockClient,(char*)&recvData,sizeof(recvData),0);


			if (SOCKET_ERROR == nRecvLen)
			{
				//pDlg->GetDlgItem(IDC_STATIC_MSG)->SetWindowText(_T("USB连接失败或无发行系统无初始化操作!"));
				closesocket(sockClient);
				sockClient=socket(AF_INET,SOCK_STREAM,0);
				break;
			}
			if (nRecvLen == 0)
			{

				TRACE(L"Recv 0\n");
				Sleep(50);
				continue;
			}

			if(/*SOCKET_ERROR != nRecvLen && */0 != nRecvLen)
			{
				if(0 == nLen && 0x31 == recvData[0] )
				{
					memcpy(msg, recvData, nRecvLen);
					nLen += nRecvLen;
				}
				else if(0 < nLen)
				{
					memcpy(msg + nLen, recvData, nRecvLen);
					nLen += nRecvLen;
				}



				if(0 < nLen )
				{
					//
					int SInitLen = recvData[1] * 0x100 + recvData[2];
					//
					if (SInitLen == nLen)
					{

						if(pDlg->AnalyseInitMsg(msg, nLen))
						{
							send(sockClient, "ok", 3, 0);
							pDlg->GetDlgItem(IDC_STATIC_MSG)->SetWindowText(_T("初始化完成,正在返回!"));
							Sleep(500);
							
							pDlg->PostMessage(WM_INITSUCCESS, 0, 0);									
						}
						else
						{
							send(sockClient, "error", 6, 0);
							Sleep(500);
							//pDlg->GetDlgItem(IDC_STATIC_USBINIT)->SetWindowText(_T("初始化失败,重新获得配置信息。"));
							pDlg->GetDlgItem(IDC_STATIC_MSG)->SetWindowText(_T("初始化失败,重新获得配置信息。"));

						}

					}
				}

			}


		}
	}
END:
	//关闭套接字
	closesocket(sockClient);
	WSACleanup();


	return 0;
}

这里你发现我设置的IP是192.168.55.100

而不是192.168.55.101的WinceIP ,为什么用100网关而不用101Wince的100,因为PC端会虚拟一个100的IP对应

在这里你会发现,当你连接USB后connect会成功,Socket默认是阻塞模式的,你会发现执行到recv的时候它却直接返回-1(当你起了服务端后,recv会死等,正常情况);

原理这里的connect不是真正的连接成功了,所以这里recv后你还应该去做判断是否真的连接成功了,这里我开始用了select模式超时,依然无法判断是否真的连接成功。

所以我这里占时做的是如果recv-1;直接从新socket去connect,(这里不知道你会不会发现问题,当用户将USB连接后而没起服务端,这里你就会反复socket创建,但是socket线程池,即原先的socket好像是2分钟才回收,根本来不及回收,不会发现过一会后socket的返回值会很大(1,3,5,7......)如此增加,我在想最终肯定会超出上限奔溃,),有人可能会说那在recv失败后线sleep下啊。多等待让socket回收啊。可惜我的用户是国安的老年人,要在不小心掉了数据线后再次插上后马上重连(recv阻塞模式死等会很久),没办法,我只能另外起线程,判断用户多久一直没操作就关闭socket不在重新创建,操作的时候如何没connect上在创建socket。这里我也采用了超时recv,因为需求不能在recv死等太久。


当然由于没用过select和时间有限,那时候的思路是这样的,采用select超时模式,因为当服务端没起来。connect是假的connect,应该和(window设备中心的一个虚拟的连接上了),这时候判断recv返回-1的情况下是否超出了超时时间,没有超出超时时间,那说明直接返回的recv-1,是前面connect是假连接。


======================================下面是服务端


static int nInitCount = 0;
	//加载套接字socket(插座)
	WORD wVersionRequested;					//typedef unsigned short WORD;
	WSADATA wsaData;						//结构体  typedef struct WSAData   WSADATA    。typedef WSADATA FAR *LPWSADATA;
	int nReg = 0;							//错误函数的检测数值传递给nReg
	SOCKET sockSvr;							//typedef _W64 unsigned int 、、SOCKET;  
	SOCKADDR_IN addrSrv;
	int nErrCode = 0;
	int bExit = 0;
	unsigned long ul = -1;

	struct timeval timeout={2,0};
	fd_set rfd;
	int nfds;

	wVersionRequested = MAKEWORD(1, 1);		//请求.1版本socket

	nReg = WSAStartup(wVersionRequested,&wsaData);//初始化
	if (0 != nReg)
	{
		printf("err code :%d",WSAGetLastError());
		return 0;
	}
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	{
		printf("VERSION DIFF");
		WSACleanup();
		return 0;
	}

	sockSvr = socket(AF_INET, SOCK_STREAM, 0); //socket(IN int af,IN int type,IN int protocol); SOCK_STREAM(使用TCP协议而不是UDP)创建socket
// 	nErrCode = ioctlsocket(sockSvr, FIONBIO, (unsigned long*)&ul);                 //设置套接字非阻塞模式
// 	if (nErrCode == SOCKET_ERROR)
// 	{
// 		//设置套接字非阻塞模式,失败处理
// 	}
	if (INVALID_SOCKET == sockSvr)             //判断sock是否创建成功
	{
		printf("err code :%d",WSAGetLastError());//获取错误类型函数WSAGetLastError()
		return 0;
	}

	//设定内部接口
	addrSrv.sin_family = AF_INET;										//启动协议
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);					//绑定地址
	addrSrv.sin_port = htons(26023);										//绑定端口

	nReg = bind(sockSvr, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));		//内部接口设定完成将整体绑定到服务器sockSvr
	if (SOCKET_ERROR == nReg)                                           //判断绑定是否成功
	{
		nErrCode = WSAGetLastError();
		if (nErrCode == WSAEADDRINUSE)									 //如果端口被占用
		{
			//printf("err code :%d,port is already used ",nErrCode);
		}
		else
		{

		}
			//printf("err code :%d",nErrCode);
		return 0;
	}

	//监听,准备接收
	listen(sockSvr, 5);									//最多同时监听个sock

	CString strMsg = _T("");
	while (TRUE)
	{
		if (WAIT_OBJECT_0 == WaitForSingleObject(dlg->m_hEventSocket,100))//结束押运箱
		{
			closesocket(sockSvr);                                                //关闭正在于客户端通信的服务端sock
			WSACleanup();//初始化关闭
			SetEvent(dlg->m_HEventExitSocket);
			return 0;
		}
		if (dlg->m_bUsbinitingTer)
		{
			if (nInitCount == 0)
			{
				strMsg.Format(_T("正在初始化%s手持终端,请等待..."),dlg->m_strTerInitName);
				dlg->m_pOutPutView->AddWarnInfo(strMsg,true);
			}
			
			SOCKADDR_IN cliAddr;
			SOCKET cliSock = -1;
			int nlen = sizeof(SOCKADDR);
			char buf[1024] = {0};


			FD_ZERO(&rfd);
			FD_SET(sockSvr,&rfd);
			nfds = select(1,&rfd,(fd_set*) 0,(fd_set*) 0,&timeout);

			if(nfds==0)
			{
				strMsg.Format(_T("请检查手持终端编号是否正确匹配,USB数据线是否正确连接!"));
				dlg->m_pOutPutView->AddWarnInfo(strMsg,false);
				dlg->m_btn_UsbInitTer.EnableWindow(TRUE);
				dlg->m_bUsbinitingTer=false;	
				continue;
			}				
			else if(nfds>0)
			{
				FD_CLR(sockSvr,&rfd);
				//accept socket
				cliSock = accept(sockSvr, (SOCKADDR*)&cliAddr, &nlen);	等待客户端请求并重新定义一个对应此次链接的socket


				if (WSAEINTR == cliSock)             //判断sock是否创建成功
				{
					//char recvBuf[100];
					/*printf("err code :%d",WSAGetLastError());//获取错误类型函数WSAGetLastError()*/
					//return 0;
				}
				//发送数据
				send(cliSock,dlg->m_initterminalbase,dlg->m_TerInitlen,0);
				char recvBuf[100];
				memset(recvBuf, 0, 100);
				Sleep(1000);
				//接收数据
				recv(cliSock,recvBuf,100,0);
				//closesocket(cliSock);
				CString back=_T("");
				back=(CString)recvBuf;


				if (back!=_T("ok"))
				{
					nInitCount++;
					if (nInitCount == 6)
					{
						nInitCount = 0;
						strMsg.Format(_T("手持终端%s初始化失败,请检查手持终端USB是否正确连接,编号是否匹配!"),dlg->m_strTerInitName);
						dlg->m_pOutPutView->AddWarnInfo(strMsg,false);
						dlg->m_btn_UsbInitTer.EnableWindow(TRUE);
						dlg->m_bUsbinitingTer=false;	
						continue;
					}
					else
					{
						strMsg.Format(_T("手持终端%s初始化失败,正在继续,请等待!"),dlg->m_strTerInitName);
						dlg->m_pOutPutView->AddWarnInfo(strMsg,false);
						Sleep(1000);			

					}

				}
				else
				{
					nInitCount = 0;
					strMsg.Format(_T("手持终端%s初始化成功!"),dlg->m_strTerInitName);
					dlg->m_pOutPutView->AddWarnInfo(strMsg,true);
					dlg->m_btn_UsbInitTer.EnableWindow(TRUE);
					dlg->m_bUsbinitingTer=false;	
					continue;
				}	

			}
			else
			{
				break;

			}
			
		}
		

	}

	closesocket(sockSvr);                                                //关闭正在于客户端通信的服务端sock
	WSACleanup();//初始化关闭
	return 0;


}



这里我是当用户PC的服务端点击按钮后发送数据,accept是原本是阻塞模式,这里用select超时模式,
dlg->m_bUsbinitingTer
用来判断用户点击了按钮让其变为ture。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【网络通信】Wince 和 PC 通过USB 用Socket 进行通信 的相关文章

  • 我的2013——学习、工作与生活

    一直觉得应该写阶段性总结 xff0c 以知道自己这段时间在干什么 xff0c 下一个阶段该干什么 xff0c 没实施过 xff1b 一直觉得学技术就应该多些博客 xff0c 以和同行共同学习交流 xff0c 分享是美德 xff0c 也是对
  • POI Excel导出样式设置

    HSSFSheet sheet 61 workbook createSheet 34 sheetName 34 创建sheet sheet setVerticallyCenter true 下面样式可作为导出左右分栏的表格模板 sheet
  • SQL强化:将相同的或连续的时间段合并

    问题描述 xff1a 有一张签到表 xff0c 需要将连续或相同的时间段合并 xff0c 即把多条记录查询合并成一条连续的时间段记录 数据表如下 xff1a DROP TABLE IF EXISTS 96 timesheets 96 CRE
  • Mysql实现数据的不重复写入(insert if not exists)以及新问题:ID自增不连续的解答

    最近做数据处理时候 xff0c 遇到一个问题 用一个id自增主键时候 xff0c 数据表中会插入大量重复数据 xff08 除ID不同 xff09 这虽然对最终数据处理结果没有影响 xff0c 但是有1个问题 xff0c 如果数据量超大 xf
  • 2014年秋找工作经历

    博主学渣一枚 xff0c 读研期间做过几个不上档次的管理系统 xff0c 学历不太好 xff0c 基础知识不太牢固 xff0c 所以校招找工作难免辛酸 记下这个过程 xff0c 以便日后回顾来时的路 9月 xff0c 酱油了 xff0c 只
  • 服务器端获取webservice客户端IP地址

    一 基于xfire发布的webservice获取客户端ip的方法 public String getClientIp String ip 61 34 34 try HttpServletRequest request 61 XFireSer
  • @Autowired,@Qualifier @Required @Resource @Component,@Service,@Controller,@Repository @PostConstruct

    1 64 Autowired 注解 xff1a 首先在使用时候需要引入配置 xff1a lt 该 BeanPostProcessor 将自动起作用 xff0c 对标注 64 Autowired 的 Bean 进行自动注入 gt lt bea
  • HTML中select标签单选多选详解

    select 元素可创建单选或多选菜单 当提交表单时 xff0c 浏览器会提交选定的项目 xff0c 或者收集用逗号分隔的多个选项 xff0c 将其合成一个单独的参数列表 xff0c 并且在将 lt select gt 表单数据提交给服务器
  • Centos7中语言如何设置成中文

    Centos系统作为开源最优秀的Linux版本 xff0c 我们在阿里云官方镜像站 xff1a https developer aliyun com mirror 找到所需Centos版本并下载安装后 xff0c 可能未注意指定系统语言 x
  • Tomcat正常启动,访问所有页面均报404异常,404异常总结

    今天遇到一个问题 xff1a Tomcat正常启动 xff0c 访问所有页面均报404异常 404异常 xff0c 很常见 xff0c 大多情况是路径错误 web xml文件映射路径写错 服务器设置 servlet的jar包未导进去或者没有
  • oracle中游标详细用法

    游标的概念 游标是SQL的一个内存工作区 xff0c 由系统或用户以变量的形式定义 游标的作用就是用于临时存储从数据库中提取的数据块 在某些情况下 xff0c 需要把数据从存放在磁盘的表中调到计算机内存中进行处理 xff0c 最后将处理结果
  • 连接2个字符串,strcat函数。

    题目描述 设计函数连接2个字符串 单个字符串的长度不超过100 不要使用系统提供的strcat函数 输入要求 输入2个字符串 xff0c 每个字符串以换行符结束 保证每个字符串中不会出现空格 输出要求 输出连接好的字符串 输入样例 Coun
  • git 下载指定历史版本

    1 选中想回退到的commit记录 xff0c 点击如图 2 选中Hard xff0c 表示该记录之后的改动全部丢弃 3 操作完之后代码会回滚到选中的位置 xff0c 这个时候不要拉取代码 xff0c 不然又拉回来了 xff1b 直接在现有
  • 摄像机内参、外参矩阵

    摄像机矩阵由P由内参矩阵和外参矩阵组成 xff0c 对摄像机矩阵进行QR分解可以得到内参矩阵和外参矩阵 在opencv的3D重建中 xff08 opencv中文网站中 xff1a 照相机定标与三维场景重建 xff09 xff0c 对摄像机的
  • 几个简单的数据点平滑处理算法

    最近在写一些数据处理的程序 经常需要对数据进行平滑处理 直接用FIR滤波器或IIR滤波器都有一个启动问题 xff0c 滤波完成后总要对数据掐头去尾 因此去找了些简单的数据平滑处理的方法 在一本老版本的 数学手册 中找到了几个基于最小二乘法的
  • 陶哲轩实分析 3.5 节习题试解

    3 5 1 第一种定义 xff1a x y 61
  • C++ 中的 std::pair 和 std::tuple

    C 43 43 中的 std pair 和 std tuple 最近在看 C 43 43 11 的标准 xff0c 发现了 std pair 和 std tuple 感觉这两个非常有用 就在这里记录一下 std pair 出现的比较早 xf
  • OpenCV 真圆度测量

    OpenCV 真圆度测量 最近一个项目需要在图像上测量一些小孔的真圆度 因此专门研究了一下真圆度计算问题 对于一个轮廓 xff0c 我们可以求出这个轮廓的外接圆和内切圆 这两个圆的半径差定义为真圆度 这个数值越小 xff0c 表示这个圆越标
  • 如何修改 CentOS 系统最大线程数

    简介 xff1a 本文主要介绍如何修改CentOS系统最大线程数 镜像下载 域名解析 时间同步请点击 阿里巴巴开源镜像站 1 安装ElasticSearch后 xff0c 配置完成 xff0c 启动服务 xff0c 系统显示类似如下 max
  • MathJax 支持的 Latex 符号总结(各种箭头符号)

    箭头符号 latex显示效果 uparrow downarrow Uparrow Downarrow updownarrow Updownarrow rightarrow

随机推荐