最近要做一个用于监控和显示自动测试柜运行状况的监控中心的项目,就需要从测试柜获取运行状况的信息,处理后显示在一台服务器上。由于以前跟着教我C++的老师做一个基于六维力传感器的工业机械臂牵引示教系统的时候,看着老师亲自写过UDP通信(传感器的数据是通过UDP的方式传出来的)相关的代码,有了一些了解,所以决定用UDP的方式来实现。由于基本是零基础,所以只能自己一点一点调试。
sendto(SOCKET s,const char *buf,int len,int flags,const sockaddr *to,int tolen)
它用SOCKET s来发送,把char型数组buf从buf[0]到buf[len-1]的所有char型元素(共len个元素)发送到指向SOCKADDR对象的指针to所表示的IP地址。tolen一般为一个SOCKADDR型对象所占的内存空间大小(即tolen=sizeof(SOCKADDR))。
另一个函数是
recvfrom(SOCKET s,const char *buf,int len,int flags,const sockaddr *from,int *fromlen)
这和sento的形参类似,用SOCKET s来接收,从指针*from指向的SOCKETADDR对象代表的IP地址接收len个char字符(也就是*from指向的IP地址发过来的前len个char型元素),并赋值给char型数组buf中的buf[0]到buf[len-1]。不过注意最后一个形参类型和sento有区别,recvfrom是int型指针(int *),而sendto是int型量。
整个代码如下:
发送端程序
#include "stdafx.h"
#include "Winsock2.h"
#include "stdio.h"
#include "windows.h"
//没有下面这句,所有的通讯函数都将报错
#pragma comment(lib,"ws2_32.lib")//必须链接这个库
#define recvAddr "10.185.32.235"
//发送端程序
void main()
{ //初始化socket库
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
// 下面的函数是连接应用程序与winsock.dll的第一个调用.
// 第一个参数是WINSOCK 版本号,第二个参数是指向WSADATA的指针.
// 该函数返回一个INT型值,通过检查这个值来确定初始化是否成功
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
printf("WSAStartup错误!!!!");
system("pause");
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
{ WSACleanup( );
return;
}
SOCKET sockClient = socket( AF_INET , SOCK_DGRAM , 0 ) ;//建立socket,设置采用UDP方式通信
SOCKADDR_IN addrSrv ; //本机接收信息时,对方的IP地址,不设置时所有IP地址发送过来的信息都会被接收到
addrSrv.sin_addr.S_un.S_addr =inet_addr(recvAddr) ;//远程主机的IP地址,127是本机的回送地址,实际没有任何网络传输
addrSrv.sin_family = AF_INET ;
addrSrv.sin_port = htons(1234) ;//远程主机的端口port
char sendBuf[10]="" ;
char recvBuf[50]="" ;
char tempBuf[50]="" ;
int len = sizeof(SOCKADDR) ;
int a=100,b=0,c=0;
char a1[3],b1[3]c1[3];
while (1)
{
itoa(a,a1,10);
itoa(b,b1,10);
itoa(c,c1,10);
_snprintf(sendBuf,9, "%3s%3s%3s",a1,b1,c1 );//将a1,b1,c1按第三个形参的格式生成一个char型数组,并将第三个形参char数组中的前9个元素写入senBuf数组的前九个位置
sendBuf[9]='0';
sendto( sockClient , sendBuf , 10 , 0 , (SOCKADDR*)&addrSrv , len ) ;//发送10个char数组
for(int i =0;i<50;i++)
{
tempBuf[i]=' ';
}
printf( "send\n" ) ;
if(b<100)
{
b+=1;
if(a>20)
b=a-15;
else if(b>10)
c=b-10;
else if(tested>5)
c=b-5;
}
else
{
a=100,b=0,c=0;
}
Sleep(1000);
}
closesocket(sockClient) ;//关闭socket
WSACleanup() ;
}
接收端程序:
#include "stdafx.h"
#include "Winsock2.h"
#include "stdio.h"
#include "windows.h"
#pragma comment(lib,"ws2_32.lib") //没有下面这句,所有的通讯函数都将报错
void main()
{ //初始化socket库
WORD wVersionRequested;
WSADATA wsaData; //wsaData用来存储系统传回的关于WINSOCK的资料
int err;
wVersionRequested = MAKEWORD( 1, 1 );
// 下面的函数是连接应用程序与winsock.dll的第一个调用.
// 第一个参数是WINSOCK 版本号,第二个参数是指向WSADATA的指针.
// 该函数返回一个INT型值,通过检查这个值来确定初始化是否成功
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) return;
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
{ WSACleanup( );
return;
}
SOCKET sockSrv = socket( AF_INET , SOCK_DGRAM , 0 ) ;
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr =inet_addr("10.185.32.235");
addrSrv.sin_family = AF_INET ,
addrSrv.sin_port = htons(1000) ;
bind( sockSrv , (SOCKADDR*)&addrSrv , sizeof(SOCKADDR) ) ;//将SOCKET和指定的IP地址端口绑定在一起,本SOCKET就用第二个形参设定好的IP端口和其他主机进行通信
char sendBuf[100]="received" ;
char recvBuf[100]="" ;
char tempBuf[200]="" ;
SOCKADDR_IN addrClient ;//这里没有设置IP地址,所以所有的IP发的UDP信息都会被本机接收到
int len = sizeof(SOCKADDR) ;
while (1)
{
recvfrom(sockSrv,recvBuf,9,0,(SOCKADDR*)&addrClient,&len) ;//接收9个char型字符并赋值给recvBuf数组的前九个元素
_snprintf(tempBuf,24,"%s say: %s\n",inet_ntoa(addrClient.sin_addr),recvBuf) ;
for(int i =0;i<50;i++)
{
tempBuf[i]=' ';
recvBuf[i]=' ';
}
sendto(sockSrv,sendBuf,9,0,(SOCKADDR*)&addrClient,len) ;
}
closesocket( sockSrv ) ;
WSACleanup() ;
}
还有做这个项目过程中发现的一些其他收获。