gige相机能不能绕开相机生产商提供的sdk,而直接取到像?
两种办法,第一,gige vision2.0说明书,第二,genicam
首先你会去干什么事?
好几年,我都没有突破,老虎吃天,不知道从哪里下抓。
神奇的事,2023年底,我遇到了genicam。
这给我打开了另一扇窗。
幸运的是,我找到了三个源程序,有一个是可以运行的在vs2022的c#下,使用wpf,说实在,我不懂wpf,c#我只会winform。
另外两个源程序,一个是c++语言版本的,他支持linux运行和windows运行,我以前搞过mfc vs c++,Linux不懂,注释掉,运行windows版本,编译不通过,一大堆问题,几度放弃。
csdn下,也有此作者的下载:
另外一个是c语言的,可是很多年前学过的c语言忘完了,以及socket通信,也忘完了。也支持linux运行和windows运行,注释掉Linux不懂,运行windows版本,编译能通过,花了好大功夫。
得到一个结论,gige相机和程序间是一问一答方式,这个很像多年前用vc++的api函数控制光驱的关闭,只需要发消息就行了,这是我对gige工业相机最大的认识,在这种信念下,就一步一步调试出来了。
这样很多知识就捡回来了,c呀,c++呀,还有socket通信呀。这个c语言版本主要提供了gige相机和程序间通信soket互问互答,虽然没结果,但这个认识很重要。
上面c++版本的程序,是可以见到相机图像的程序,调试成功完成后,最好用windows的socket,不要用gil以及其他第三方包,你理解了这个c语言版本,c++版本就能有很大的突破。
最好的wpf版本,c#写的,有时能运行,出图像,有时不能,我有点怀疑c#的机制,这些都是次要的,关键是,他能运行,你可以一步一步看下去,理解代码,c++版本的调试成功,这个c#可出图版本功劳巨大,虽然不懂wpf,上面走了很多冤枉路,但是wpf也懂了不少,没人教,也能学个半吊子。
还有一个很重要的工具,就是wireshark,他能监控出来,你的程序出现图像显示,执行了那些命令,我有监控海康自带的gige工业相机的连接,打开和显示。
并和我调试的程序对比,突破重重障碍。
后来又写了一版gige工业相机取像,起名“一步登天”,因为我只用收发命令就能得到gige工业相机的图像,其他研究过的,大部用不着了,而你就会发现gige vision2.0使用说明书和genicam只是协议而已。
我的c语言版本,c#版本不存在相机取像问题,没有wpf有时打不开的情况。
我专门买了海康的500万gige工业相机来做这件事,结果是令人满意的。
但是,换作basler gige200万工业相机,不行,换作海康2000万彩色gige工业相机也打不开图像,也就是说其他品牌相机也不行,你应该知道秘密在哪里,在wireshark里,监控对比后,修改程序中的互动命令,一定可以。
看来,还是没有一步登天,但这是一件有意义的事情。
c语言源代码如下:
// Changshigegesecond.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
//#ifdef _WINDOWS_
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
//Windows.h 标头默认包含 Windows Sockets 1.1 的 Winsock.h 头文件
//Winsock.h 头文件中的声明将与 Windows Sockets 2.0 所需的 Winsock2.h 头文件中的声明冲突
//WIN32_LEAN_AND_MEAN宏可防止 Windows.h 标头包含 Winsock.h
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
//#include <ws2tcpip.h>
#include <mswsock.h>
#include <malloc.h>
//#include "winsock2.h"
//#include <windows.h>
#ifndef ETH_ALEN
#define ETH_ALEN 6 // 以太网地址大小
#define ETH_HLEN 14 // 以太网头部大小
#define ETH_DATA_LEN 1500 // 最大帧负载数据大小
#define ETH_FRAME_LEN 1514 // 最大帧大小,头部+负载数据
#endif
//#else
//#include <unistd.h>
//#include <sys/types.h> /* See NOTES */
//#include <sys/socket.h>
//#include <sys/ioctl.h>
//#include <net/if.h>
//#include <sys/socket.h>
//#include <netinet/in.h>
//#include <arpa/inet.h>
//#include <netinet/if_ether.h>
//#include <netinet/in.h>
//#include <linux/sockios.h>
//#include <net/route.h>
//#endif
#include <errno.h>
//#include <iostream>
#include <iphlpapi.h>
#include <sstream>
#include <iomanip>
//using namespace std;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
//#ifdef _WINDOWS_//这个和linux相关,回头研究一下20240310
//#endif
//使用 Winsock 的应用程序必须与 Ws2_32.lib 库文件链接
#pragma comment(lib, "Ws2_32.lib")
#if 1//most hardware
#define MY_DEV_NAME "eth0"
#else
#define MY_DEV_NAME "ens33"
#endif
//char m_szLocalIp[32]="192.168.1.230";//本地千兆网卡的ip?
//char m_szLocalMask[32]="255.255.255.0";
//char m_szLocalGateway[32]="192.168.1.254";
char m_szLocalIp[32]="192.168.20.48";//本地千兆网卡的ip?
char m_szLocalMask[32]="255.255.255.0";
char m_szLocalGateway[32]="192.168.20.254";
char m_szLocalMac[32];
uint8 m_LocalMacAddr[ETH_ALEN];
int SetIfAddr(char *ifname, char *Ipaddr, char *mask, char *gateway);
int GetIfAddr(char *ifname, char *Ipaddr, char *mask, char *gateway);
int addRoute(char *ipAddr, char *mask,char *gateWay,char* devName);
char m_szRemoteIp[32];//接收到远端千兆网卡的ip?
char m_szRemoteMask[32];
char m_szRemoteGateway[32];
char m_szRemoteMac[32];
uint32 m_dwRemotePort;
struct gvcp_cmd_header{
uint8 cMsgKeyCode;//0x42
uint8 cFlag;//0x11 allow broadcast ack;ack required
uint16 wCmd;//discovery_cmd=2;FORCEIP_CMD = 4;READREG_CMD=0x80
uint16 wLen;//payload length
uint16 wReqID;// request id = 1;READREG id=12345
};
struct gvcp_forceip_payload{
uint8 Mac[8];//last 6 byte
uint8 CurIP[16];//last 4 byte
uint8 SubMask[16];//last 4 byte
uint8 Gateway[16];//last 4 byte
};
struct gvcp_ack_header{
uint16 wStatus;//success=0;
uint16 wAck;//discover_ack=3;forceip_ack=5;READREG_ACK=0x81
uint16 wLen;
uint16 wReqID;
};
struct gvcp_ack_payload{
uint32 dwSpecVer;
uint32 dwDevMode;
uint8 Mac[8];//last 6 byte
uint32 dwSupIpSet;
uint32 dwCurIpSet;
//uint8 unused1[12];
uint8 CurIP[16];//last 4 byte
uint8 SubMask[16];//last 4 byte
uint8 Gateway[16];//last 4 byte
char szFacName[32];//first
char szModelName[32];//first
char szDevVer[32];
char szFacInfo[48];
char szSerial[16];
char szUserName[16];
};
struct gvcp_discover_cmd{
struct gvcp_cmd_header header;
};
struct gvcp_discover_ack{
struct gvcp_ack_header header;
struct gvcp_ack_payload payload;
};
struct gvcp_forceip_cmd{
struct gvcp_cmd_header header;
struct gvcp_forceip_payload payload;
};
struct gvcp_forceip_ack{
struct gvcp_ack_header header;
};
struct gvcp_readreg_cmd{
struct gvcp_cmd_header header;
uint32 dwRegAddr;
};
struct gvcp_readreg_ack{
struct gvcp_ack_header header;
uint32 dwRegValue;
};
struct gvcp_writereg_cmd {
struct gvcp_cmd_header header;
uint32 dwRegAddr;
uint32 dwRegValue;
};
struct gvcp_writereg_ack {
struct gvcp_ack_header header;
};
struct gvcp_readmem_cmd {
struct gvcp_cmd_header header;
uint32 dwMemAddr;
uint32 dwMemCount;//last 2 byte
};
struct gvcp_readmem_ack {
struct gvcp_ack_header header;
uint32 dwMemAddr;
char* pMemBuf;
};
#define GVCP_DISCOVERY_CMD 2
#define GVCP_DISCOVERY_ACK 3
#define GVCP_FORCEIP_CMD 4
#define GVCP_FORCEIP_ACK 5
#define GVCP_READREG_CMD 0x80
#define GVCP_READREG_ACK 0x81
#define GVCP_WRITEREG_CMD 0x82
#define GVCP_WRITEREG_ACK 0x83
#define GVCP_READMEM_CMD 0x84
#define GVCP_READMEM_ACK 0x85
//#ifndef ETH_ALEN
//#define ETH_ALEN 6 // 以太网地址大小
//#define ETH_HLEN 14 // 以太网头部大小
//#define ETH_DATA_LEN 1500 // 最大帧负载数据大小
//#define ETH_FRAME_LEN 1514 // 最大帧大小,头部+负载数据
//#endif
int getLoaclMac(char *szMac) //获取本地的mac
{
#ifndef _WINDOWS_
char *device=MY_DEV_NAME; //eth0是网卡设备名
//unsigned char macaddr[ETH_ALEN]; //ETH_ALEN(6)是MAC地址长度
struct ifreq req;
int err,i;
int s;
s=socket(AF_INET,SOCK_DGRAM,0); //internet协议族的数据报类型套接口
strcpy(req.ifr_name,device); //将设备名作为输入参数传入
err=ioctl(s,SIOCGIFHWADDR,&req); //执行取MAC地址操作
close(s);
if(err != -1) {
memcpy(m_LocalMacAddr,req.ifr_hwaddr.sa_data,ETH_ALEN); //取输出的MAC地址
for(i = 0; i < ETH_ALEN; i++) {
sprintf(szMac, "%s%02x",szMac, m_LocalMacAddr[i]&0xff);
if(i != ETH_ALEN - 1) {
sprintf(szMac, "%s:", szMac);
}
}
} else {
return -1;
}
#else
bool ret = false;
ULONG outBufLen = sizeof(IP_ADAPTER_ADDRESSES);
PIP_ADAPTER_ADDRESSES pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
if (pAddresses == NULL)
return false;
// Make an initial call to GetAdaptersAddresses to get the necessary size into the ulOutBufLen variable
if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW)
{
free(pAddresses);
pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
if (pAddresses == NULL)
return false;
}
if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == NO_ERROR)
{
// If successful, output some information from the data we received
for (PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses != NULL; pCurrAddresses = pCurrAddresses->Next)
{
// 确保MAC地址的长度为 00-00-00-00-00-00
if (pCurrAddresses->PhysicalAddressLength != 6)
continue;
//char acMAC[32];
memcpy(m_LocalMacAddr, pCurrAddresses->PhysicalAddress, ETH_ALEN); //取输出的MAC地址
sprintf(szMac, "%02X:%02X:%02X:%02X:%02X:%02X",
int(pCurrAddresses->PhysicalAddress[0]),
int(pCurrAddresses->PhysicalAddress[1]),
int(pCurrAddresses->PhysicalAddress[2]),
int(pCurrAddresses->PhysicalAddress[3]),
int(pCurrAddresses->PhysicalAddress[4]),
int(pCurrAddresses->PhysicalAddress[5]));
//macOUT = acMAC;
ret = true;
break;
}
}
free(pAddresses);
#endif
return 0;
}
int gvcp_ack_discover(int iFd,char* szIp,char* szMask,char* szGateway, uint16 wReqID,uint32 dwPort,uint8* pMac)
{
//char rgMessage[128] = "I am sending message to you!";
//int iFd;
int iSendbytes;
int iOptval = 1;
struct sockaddr_in Addr;
int bNeedClose=0;
if(iFd<0)
{
if ((iFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("socket fail\n");
return -1;
}
bNeedClose=1;
}
if (setsockopt(iFd, SOL_SOCKET, SO_REUSEADDR, (char*)&iOptval, sizeof(int)) < 0)
{
printf("setsockopt failed!");
}
/* if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, (char*)&iOptval, sizeof(int)) < 0)
{
printf("setsockopt failed!");
}*/
BOOL bBroadcast = true;
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)) < 0)
{
printf("setsockopt SO_BROADCAST failed!");
}
memset(&Addr, 0, sizeof(struct sockaddr_in));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = inet_addr("192.168.20.54");
Addr.sin_port = htons(dwPort);
/*memset(&Addr, 0, sizeof(struct sockaddr_in));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = inet_addr("255.255.255.255");
Addr.sin_port = htons(3956);*/
//static struct gvcp_discover_cmd cmd_msg;
//memset(&cmd_msg, 0, sizeof(struct gvcp_discover_ack));
static struct gvcp_discover_ack ack_msg;
memset(&ack_msg, 0, sizeof(struct gvcp_discover_ack));
ack_msg.header.wStatus=htons(0);
ack_msg.header.wAck=htons(GVCP_DISCOVERY_ACK);
ack_msg.header.wLen=htons(sizeof(struct gvcp_ack_payload));
ack_msg.header.wReqID=htons(1);
ack_msg.payload.dwSpecVer=htonl(0x010002);;
ack_msg.payload.dwDevMode=htonl(1);
//uint8 MyMac[6]={0xc4,0x2f,0x90,0xf1,0x71,0x3e};
memcpy(&ack_msg.payload.Mac[2],m_LocalMacAddr,6);
ack_msg.payload.dwSupIpSet=htonl(0x80000007);
ack_msg.payload.dwCurIpSet=htonl(0x00005);
//uint8 unused1[12];
*((uint32*)&ack_msg.payload.CurIP[12])=inet_addr(m_szLocalIp);//last 4 byte
*((uint32*)&ack_msg.payload.SubMask[12])=inet_addr(m_szLocalMask);//last 4 byte
*((uint32*)&ack_msg.payload.Gateway[12])=inet_addr(m_szLocalGateway);//last 4 byte
//strcpy(ack_msg.payload.szFacName,"GEV");//first
//strcpy(ack_msg.payload.szModelName,"MV-AA003-50GM");//first
//strcpy(ack_msg.payload.szDevVer,"V2.8.6 180210 143913");
//strcpy(ack_msg.payload.szFacInfo,"GEV");
//strcpy(ack_msg.payload.szSerial,"00C31976084");
//strcpy(ack_msg.payload.szUserName,"");
strcpy(ack_msg.payload.szFacName,"GEV");//first
strcpy(ack_msg.payload.szModelName,"MV-CE050-30GM");//first
strcpy(ack_msg.payload.szDevVer,"V2.10.0 191122 355697");
strcpy(ack_msg.payload.szFacInfo,"GEV");
strcpy(ack_msg.payload.szSerial,"00E36658695");
strcpy(ack_msg.payload.szUserName,"");
char* rgMessage=(char*)&ack_msg;
uint32 dwMsgLen = sizeof(struct gvcp_discover_ack);
//char* rgMessage = (char*)&cmd_msg;
//uint32 dwMsgLen = sizeof(struct gvcp_discover_cmd);
//while (1)
{
if ((iSendbytes = sendto(iFd, rgMessage, dwMsgLen, 0, (struct sockaddr*)&Addr, sizeof(struct sockaddr))) == -1)
{
printf("sendto fail, errno=%d,%s\n", errno,strerror(errno));
return -1;
}
printf("gvcp_ack_discover=%s, rgMessageLen=%d,iSendbytes=%d\n", rgMessage, dwMsgLen, iSendbytes);
//sleep(1);
}
if(bNeedClose>0)
{
#ifdef _WINDOWS_
closesocket(iFd);
#else
close(iFd);
#endif
}
return 0;
}
int gvcp_ask_forceip(int iFd, uint16 wReqID, uint32 dwPort)
{
//char rgMessage[128] = "I am sending message to you!";
//int iFd;
int iSendbytes;
struct sockaddr_in Addr;
int bNeedClose = 0;
if (iFd < 0)
{
if ((iFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("socket fail\n");
return -1;
}
bNeedClose = 1;
}
int iOptval = 1;
#ifdef _WINDOWS_
if (setsockopt(iFd, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&iOptval, sizeof(int)) < 0)
{
printf("setsockopt SO_REUSEADDR failed!");
}
BOOL bBroadcast = true;
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)) < 0)
{
printf("setsockopt SO_BROADCAST failed!");
}
#else
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &iOptval, sizeof(int)) < 0)
{
printf("setsockopt failed!");
}
#endif
memset(&Addr, 0, sizeof(struct sockaddr_in));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = inet_addr("255.255.255.255");
Addr.sin_port = htons(dwPort);
static struct gvcp_forceip_ack my_msg;
memset(&my_msg, 0, sizeof(struct gvcp_forceip_ack));
my_msg.header.wStatus = htons(0);
my_msg.header.wAck = htons(GVCP_FORCEIP_ACK);
my_msg.header.wLen = htons(0);
my_msg.header.wReqID = htons(wReqID );
char* rgMessage = (char*)&my_msg;
uint32 dwMsgLen = sizeof(struct gvcp_forceip_ack);
//while (1)
{
if ((iSendbytes = sendto(iFd, rgMessage, dwMsgLen, 0, (struct sockaddr*)&Addr, sizeof(struct sockaddr))) == -1)
{
printf("sendto fail, errno=%d,%s\n", errno, strerror(errno));
return -1;
}
printf("gvcp_ask_forceip=%s, rgMessageLen=%d,iSendbytes=%d\n", rgMessage, dwMsgLen, iSendbytes);
//sleep(1);
}
if (bNeedClose > 0)
{
#ifdef _WINDOWS_
closesocket(iFd);
#else
close(iFd);
#endif
}
return 0;
}
int gvcp_ask_readreg(int iFd, uint16 wReqID,uint32 dwPort, uint32 dwRegAddr, uint32 dwRegValue)
{
//char rgMessage[128] = "I am sending message to you!";
//int iFd;
int iSendbytes;
struct sockaddr_in Addr;
int bNeedClose = 0;
if (iFd < 0)
{
if ((iFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("socket fail\n");
return -1;
}
bNeedClose = 1;
}
int iOptval = 1;
#ifdef _WINDOWS_
if (setsockopt(iFd, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&iOptval, sizeof(int)) < 0)
{
printf("setsockopt SO_REUSEADDR failed!");
}
BOOL bBroadcast = true;
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)) < 0)
{
printf("setsockopt SO_BROADCAST failed!");
}
#else
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &iOptval, sizeof(int)) < 0)
{
printf("setsockopt failed!");
}
#endif
memset(&Addr, 0, sizeof(struct sockaddr_in));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = inet_addr("255.255.255.255");
Addr.sin_port = htons(dwPort);
static struct gvcp_readreg_ack my_msg;
memset(&my_msg, 0, sizeof(struct gvcp_readreg_ack));
my_msg.header.wStatus = htons(0);
my_msg.header.wAck = htons(GVCP_READREG_ACK);
my_msg.header.wLen = htons(4);
my_msg.header.wReqID = htons(wReqID);
my_msg.dwRegValue = htonl(dwRegValue);;
char* rgMessage = (char*)&my_msg;
uint32 dwMsgLen = sizeof(struct gvcp_readreg_ack);
//while (1)
{
if ((iSendbytes = sendto(iFd, rgMessage, dwMsgLen, 0, (struct sockaddr*)&Addr, sizeof(struct sockaddr))) == -1)
{
printf("sendto fail, errno=%d,%s\n", errno, strerror(errno));
return -1;
}
printf("gvcp_ask_readreg=%s, rgMessageLen=%d,iSendbytes=%d\n", rgMessage, dwMsgLen, iSendbytes);
//sleep(1);
}
if (bNeedClose > 0)
{
#ifdef _WINDOWS_
closesocket(iFd);
#else
close(iFd);
#endif
}
return 0;
}
int gvcp_ask_writereg(int iFd, uint16 wReqID, uint32 dwPort)
{
//char rgMessage[128] = "I am sending message to you!";
//int iFd;
int iSendbytes;
struct sockaddr_in Addr;
int bNeedClose = 0;
if (iFd < 0)
{
if ((iFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("socket fail\n");
return -1;
}
bNeedClose = 1;
}
int iOptval = 1;
#ifdef _WINDOWS_
if (setsockopt(iFd, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&iOptval, sizeof(int)) < 0)
{
printf("setsockopt SO_REUSEADDR failed!");
}
BOOL bBroadcast = true;
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)) < 0)
{
printf("setsockopt SO_BROADCAST failed!");
}
#else
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &iOptval, sizeof(int)) < 0)
{
printf("setsockopt failed!");
}
#endif
memset(&Addr, 0, sizeof(struct sockaddr_in));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = inet_addr("255.255.255.255");
Addr.sin_port = htons(dwPort);
static struct gvcp_writereg_ack my_msg;
memset(&my_msg, 0, sizeof(struct gvcp_writereg_ack));
my_msg.header.wStatus = htons(0);
my_msg.header.wAck = htons(GVCP_WRITEREG_ACK);
my_msg.header.wLen = htons(0);
my_msg.header.wReqID = htons(wReqID);
char* rgMessage = (char*)&my_msg;
uint32 dwMsgLen = sizeof(struct gvcp_writereg_ack);
//while (1)
{
if ((iSendbytes = sendto(iFd, rgMessage, dwMsgLen, 0, (struct sockaddr*)&Addr, sizeof(struct sockaddr))) == -1)
{
printf("sendto fail, errno=%d,%s\n", errno, strerror(errno));
return -1;
}
printf("gvcp_ask_writereg=%s, rgMessageLen=%d,iSendbytes=%d\n", rgMessage, dwMsgLen, iSendbytes);
//sleep(1);
}
if (bNeedClose > 0)
{
#ifdef _WINDOWS_
closesocket(iFd);
#else
close(iFd);
#endif
}
return 0;
}
int gvcp_cmd_discover(int iFd)
{
//char rgMessage[128] = "I am sending message to you!";
//int iFd;
int iSendbytes;
struct sockaddr_in Addr;
int bNeedClose = 0;
if (iFd < 0)
{
if ((iFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("socket fail\n");
return -1;
}
bNeedClose = 1;
}
int iOptval = 1;
#ifdef _WINDOWS_
if (setsockopt(iFd, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&iOptval, sizeof(int)) < 0)
{
printf("setsockopt SO_REUSEADDR failed!");
}
BOOL bBroadcast = true;
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)) < 0)
{
printf("setsockopt SO_BROADCAST failed!");
}
#else
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &iOptval, sizeof(int)) < 0)
{
printf("setsockopt failed!");
}
#endif
memset(&Addr, 0, sizeof(struct sockaddr_in));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = inet_addr("255.255.255.255");
Addr.sin_port = htons(3956);
static struct gvcp_discover_cmd cmd_msg;
memset(&cmd_msg, 0, sizeof(struct gvcp_discover_ack));
cmd_msg.header.cMsgKeyCode = 0x42;
cmd_msg.header.cFlag=0x11;//0x11 allow broadcast ack;ack required
cmd_msg.header.wCmd= htons(GVCP_DISCOVERY_CMD);//discovery_cmd=2;FORCEIP_CMD = 4;READREG_CMD=0x80
cmd_msg.header.wLen = htons(0);//payload length
cmd_msg.header.wReqID = htons(1);// request id = 1;READREG id=12345
char* rgMessage = (char*)&cmd_msg;
uint32 dwMsgLen = sizeof(struct gvcp_discover_cmd);
//while (1)
{
if ((iSendbytes = sendto(iFd, rgMessage, dwMsgLen, 0, (struct sockaddr*)&Addr, sizeof(struct sockaddr))) == -1)
{
printf("sendto fail, errno=%d,%s\n", errno, strerror(errno));
return -1;
}
printf("gvcp_cmd_discover=%s, rgMessageLen=%d,iSendbytes=%d\n", rgMessage, dwMsgLen, iSendbytes);
//sleep(1);
}
if (bNeedClose > 0)
{
#ifdef _WINDOWS_
closesocket(iFd);
#else
close(iFd);
#endif
}
return 0;
}
int gvcp_cmd_discover(int iFd,bool isreadreg)
{
//char rgMessage[128] = "I am sending message to you!";
//int iFd;
int iSendbytes;
struct sockaddr_in Addr;
int bNeedClose = 0;
if (iFd < 0)
{
if ((iFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("socket fail\n");
return -1;
}
bNeedClose = 1;
}
int iOptval = 1;
#ifdef _WINDOWS_
if (setsockopt(iFd, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&iOptval, sizeof(int)) < 0)
{
printf("setsockopt SO_REUSEADDR failed!");
}
BOOL bBroadcast = true;
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL)) < 0)
{
printf("setsockopt SO_BROADCAST failed!");
}
#else
if (setsockopt(iFd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &iOptval, sizeof(int)) < 0)
{
printf("setsockopt failed!");
}
#endif
memset(&Addr, 0, sizeof(struct sockaddr_in));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = inet_addr("255.255.255.255");
Addr.sin_port = htons(3956);
static struct gvcp_discover_cmd cmd_msg;
memset(&cmd_msg, 0, sizeof(struct gvcp_discover_ack));
cmd_msg.header.cMsgKeyCode = 0x42;
cmd_msg.header.cFlag=0x11;//0x11 allow broadcast ack;ack required
//cmd_msg.header.wCmd= htons(GVCP_DISCOVERY_CMD);//discovery_cmd=2;FORCEIP_CMD = 4;READREG_CMD=0x80
//cmd_msg.header.wLen = htons(0);//payload length
//cmd_msg.header.wReqID = htons(1);// request id = 1;READREG id=12345
cmd_msg.header.wCmd= htons(0x80);//discovery_cmd=2;FORCEIP_CMD = 4;READREG_CMD=0x80
cmd_msg.header.wLen = htons(0);//payload length
cmd_msg.header.wReqID = htons(1);// request id = 1;READREG id=12345
char* rgMessage = (char*)&cmd_msg;
uint32 dwMsgLen = sizeof(struct gvcp_discover_cmd);
//while (1)
{
if ((iSendbytes = sendto(iFd, rgMessage, dwMsgLen, 0, (struct sockaddr*)&Addr, sizeof(struct sockaddr))) == -1)
{
printf("sendto fail, errno=%d,%s\n", errno, strerror(errno));
return -1;
}
printf("gvcp_cmd_discover=%s, rgMessageLen=%d,iSendbytes=%d\n", rgMessage, dwMsgLen, iSendbytes);
//sleep(1);
}
if (bNeedClose > 0)
{
#ifdef _WINDOWS_
closesocket(iFd);
#else
close(iFd);
#endif
}
return 0;
}
//#ifdef _WINDOWS_
//extern void InitConsoleWindow();
//int GvcpServer(void)
//#else
int _tmain(int argc, _TCHAR* argv[])
//#endif
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData);
printf("wVersion: %d.%d\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
printf("wHighVersion: %d.%d\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
printf("szDescription: %s\n", wsaData.szDescription);
printf("szSystemStatus: %s\n", wsaData.szSystemStatus);
// ...
if(1)
{
//Linux下C语言获取网卡信息(IPv4)
int iRtn = GetIfAddr(MY_DEV_NAME, m_szLocalIp, m_szLocalMask, m_szLocalGateway);
if(iRtn<0) //Linux下C语言重置网卡信息(IPv4)
{
printf("GetIfAddr Error(%d) -> ResetIfAddr\n",iRtn);
iRtn = SetIfAddr(MY_DEV_NAME, m_szLocalIp, m_szLocalMask, m_szLocalGateway);
if(iRtn<0)
{
printf("SetIfAddr Error(%d)\n", iRtn);
}
}
//在网络通信中,路由是指传输数据包的路径。当一个数据包需要从一个网络发送到另一个网络时,
// 它需要经过一系列的路由器,这些路由器会根据预设的路由表来决定应该将数据包发送到哪个方向的网络。
// 静态路由是手动配置的路由,它不会随着网络拓扑的变化而自动更新。在某些情况下,
// 需要手动添加静态路由来实现网络通信,这时就需要使用route add命令
iRtn = addRoute("255.255.255.0", "255.255.255.0", m_szLocalGateway, MY_DEV_NAME);
if(iRtn<0)
{
printf("addRoute Error(%d)\n", iRtn);
}
int iAddrLength;
char rgMessage[2014];
int iOptval = 1;
int iFd;
struct sockaddr_in Addr;
//下面与tcpip正常步骤相似,udp
if ((iFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("socket fail\n");
return -1;
}
else
{
printf("socket ok\n");
}
if (setsockopt(iFd, SOL_SOCKET, SO_REUSEADDR, (char*)&iOptval, sizeof(int)) < 0)
{
printf("setsockopt failed!\n");
}
else
{
printf("setsockopt ok\n");
}
memset(&Addr, 0, sizeof(struct sockaddr_in));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = INADDR_ANY;
Addr.sin_port = htons(3956);//这里使用的端口号也是3956
iAddrLength = sizeof(Addr);
if (bind(iFd, (struct sockaddr *)&Addr, sizeof(Addr)) == -1)//绑定
{
printf("bind failed!\n");
}
else
{
printf("bind ok\n");
}
int iTryCount = 10;
bool DISCOVERYed=false;
while (1)
{
if(!DISCOVERYed)
{
gvcp_cmd_discover(iFd);//要先发一个探索包吗?如果发,应该携带本地的port和ip
Sleep(200);
}else
{
gvcp_cmd_discover(iFd,true);
Sleep(200);
}
int iRecvLen=0;
if ((iRecvLen=recvfrom(iFd, rgMessage, sizeof(rgMessage), 0, (struct sockaddr *)&Addr, &iAddrLength)) == -1)
{
printf("recv failed!\n");
}//本地接受到远端的消息
printf("recv len =%d\n", iRecvLen);
unsigned short* pBuf = (unsigned short*)rgMessage;
strncpy(m_szRemoteIp, inet_ntoa(Addr.sin_addr), 16);
if('5'==m_szRemoteIp[11]&&'4'==m_szRemoteIp[12]) DISCOVERYed=true;
strncpy(m_szRemoteMask, "255.255.255.0", 16);
strncpy(m_szRemoteGateway, inet_ntoa(Addr.sin_addr), 16);
m_dwRemotePort = ntohs(Addr.sin_port);
getLoaclMac(m_szLocalMac);//本地的ip,port和mac不同吗?
if (iRecvLen >= 8)
{
printf("recv from %s:%d-%04x-%04x-%04x-%04x\n",
inet_ntoa(Addr.sin_addr), ntohs(Addr.sin_port),
ntohs(pBuf[0]), ntohs(pBuf[1]), ntohs(pBuf[2]), ntohs(pBuf[3]));
struct gvcp_cmd_header* pHeader = (struct gvcp_cmd_header*)rgMessage;
static struct gvcp_cmd_header m_CmdHeader;
m_CmdHeader.cMsgKeyCode = pHeader->cMsgKeyCode;// 0x42;允许广播 ack
m_CmdHeader.cFlag = pHeader->cFlag;//0x11 allow broadcast ack;ack required
m_CmdHeader.wCmd = ntohs(pHeader->wCmd);//discovery_cmd=2;FORCEIP_CMD = 4;READREG_CMD=0x80
m_CmdHeader.wLen = ntohs(pHeader->wLen);//payload length
m_CmdHeader.wReqID = ntohs(pHeader->wReqID);// request id = 1;READREG id=12345
if (m_CmdHeader.cMsgKeyCode == 0x42 && m_CmdHeader.wCmd == GVCP_DISCOVERY_CMD)
{
//要先发一个探索包吗?如果发,应该携带本地的port和ip
//这里是gvcp发现回应,还要携带本地的mac地址m_LocalMacAddr
gvcp_ack_discover(iFd, m_szLocalIp, m_szLocalMask, m_szLocalGateway, m_CmdHeader.wReqID, m_dwRemotePort, m_LocalMacAddr);
}
else if (m_CmdHeader.cMsgKeyCode == 0x42 && m_CmdHeader.wCmd == GVCP_FORCEIP_CMD&&iRecvLen>=sizeof(struct gvcp_forceip_cmd))
{//如果是收到强力ip命令,force有力量的意思,f=ma
struct sockaddr_in GetAddr;
memset(&GetAddr, 0, sizeof(struct sockaddr_in));
GetAddr.sin_family = AF_INET;
GetAddr.sin_addr.s_addr = INADDR_ANY;
GetAddr.sin_port = htons(3956);
struct gvcp_forceip_cmd* pMyCmd = (struct gvcp_forceip_cmd*)rgMessage;
uint8 GetMac[6];// = { 0xc4,0x2f,0x90,0xf1,0x71,0x3e };
memcpy(GetMac, &(pMyCmd->payload.Mac[2]), 6);
printf("maccmp %s:%02x:%02x:%02x:%02x:%02x:%02x\n",m_szLocalMac,
GetMac[0],GetMac[1],GetMac[2],GetMac[3],GetMac[4],GetMac[5]);
if (memcmp(m_LocalMacAddr, GetMac, 6) == 0)//匹配成功
{
GetAddr.sin_addr.s_addr = *((uint32*)&pMyCmd->payload.CurIP[12]);// = inet_addr("192.168.101.57");//last 4 byte
strncpy(m_szLocalIp, inet_ntoa(GetAddr.sin_addr), 16);
GetAddr.sin_addr.s_addr = *((uint32*)&pMyCmd->payload.SubMask[12]);// = inet_addr("255.255.255.0");//last 4 byte
strncpy(m_szLocalMask, "255.255.255.0", 16);
GetAddr.sin_addr.s_addr = *((uint32*)&pMyCmd->payload.Gateway[12]);// = inet_addr("192.168.101.254");//last 4 byte
strncpy(m_szLocalGateway, inet_ntoa(GetAddr.sin_addr), 16);
if(SetIfAddr(MY_DEV_NAME, m_szLocalIp, m_szLocalMask, m_szLocalGateway)<0)
printf("SetIfAddr Failed");
//reget if addr
GetIfAddr(MY_DEV_NAME, m_szLocalIp, m_szLocalMask, m_szLocalGateway);
//struct gvcp_forceip_payload
gvcp_ask_forceip(iFd, m_CmdHeader.wReqID, m_dwRemotePort);
}
}
else if (m_CmdHeader.cMsgKeyCode == 0x42 && m_CmdHeader.wCmd == GVCP_READREG_CMD&&iRecvLen >= sizeof(struct gvcp_readreg_cmd))
{//如果接受是读寄存器的命令
struct gvcp_readreg_cmd* pMyCmd = (struct gvcp_readreg_cmd*)rgMessage;
uint32 dwRegAddr = ntohl(pMyCmd->dwRegAddr);
uint32 dwRegValue = 0;
if (dwRegAddr == 0x0014)//Current IP Configuration
{
//DHCP bit1
//LLA bit2
dwRegValue = 0x04;
}
else if (dwRegAddr == 0x00934)//(Gvcp Capability)
{
dwRegValue = 0xf8400007;//
}
else if (dwRegAddr == 0x00938)//heartbeat timeout
{
dwRegValue = 3000;//ms
}
else if (dwRegAddr == 0x00a00)//CCP (Control Channel Privilege)
{
dwRegValue = 0;
}
printf("readreg:%08x=%08x\n",dwRegAddr,dwRegValue);
//向相机发出读寄存器询问
gvcp_ask_readreg(iFd, m_CmdHeader.wReqID, m_dwRemotePort, dwRegAddr, dwRegValue);
}
else if (m_CmdHeader.cMsgKeyCode == 0x42 && m_CmdHeader.wCmd == GVCP_WRITEREG_CMD&&iRecvLen >= sizeof(struct gvcp_writereg_cmd))
{//如果是写gvcp寄存器命令GVCP_WRITEREG_CMD
struct gvcp_writereg_cmd* pMyCmd = (struct gvcp_writereg_cmd*)rgMessage;
uint32 dwRegAddr = ntohl(pMyCmd->dwRegAddr);
uint32 dwRegValue = ntohl(pMyCmd->dwRegValue);
//下面是解读收到消息的结果
if (dwRegAddr == 0x0014)//Current IP Configuration
{
//DHCP bit1
//LLA bit2
//dwRegValue = 0x04;
if(dwRegValue&0x02)
printf("Set DHCP Enable\n");
if(dwRegValue&0x04)
printf("Set LLA Enable\n");
}
else if (dwRegAddr == 0x00934)//(Gvcp Capability)
{
//dwRegValue = 0xf8400007;//
printf("Set Gvcp Capability:%08x\n",dwRegValue);
}
else if (dwRegAddr == 0x00938)//heartbeat timeout
{
//dwRegValue = 3000;//ms
printf("Set heartbeat timeout:%d\n",dwRegValue);
}
else if (dwRegAddr == 0x00a00)//CCP (Control Channel Privilege)
{
//dwRegValue = 0;
printf("Set CCP:%08x\n",dwRegValue);
}
gvcp_ask_writereg(iFd, m_CmdHeader.wReqID, m_dwRemotePort);
}
}
}
#ifdef _WINDOWS_
closesocket(iFd);
#else
close(iFd);
#endif
}
// ...
WSACleanup();
return 0;
}
int SetIfAddr(char *ifname, char *Ipaddr, char *mask, char *gateway)
{
int fd=0;
int rc=0;
#ifdef _WINDOWS_
#else
struct ifreq ifr;
struct sockaddr_in *sin;
struct rtentry rt;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
perror("socket error");
close(fd);
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ifname);
sin = (struct sockaddr_in*)&ifr.ifr_addr;
sin->sin_family = AF_INET;
//ipaddr
if (inet_aton(Ipaddr, &(sin->sin_addr)) < 0)
{
perror("inet_aton ipaddr error");
close(fd);
return -2;
}
uint32 dwLocalIp = sin->sin_addr.s_addr;
if (ioctl(fd, SIOCSIFADDR, &ifr) < 0)
{
perror("ioctl SIOCSIFADDR error");
close(fd);
return -3;
}
//netmask
if (inet_aton(mask, &(sin->sin_addr)) < 0)
{
perror("inet_pton netmask error");
close(fd);
return -4;
}
if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0)
{
perror("ioctl");
close(fd);
return -5;
}
//boardcast
sin->sin_addr.s_addr = (dwLocalIp&0x00FFFFFF)|0xFF000000;
//if (inet_aton(gateway, &(sin->sin_addr)) < 0)
//{
// perror("inet_pton boardcast error");
// close(fd);
// return -8;
//}
if (ioctl(fd, SIOCSIFBRDADDR, &ifr) < 0)
{
perror("ioctl");
close(fd);
return -9;
}
//gateway
memset(&rt, 0, sizeof(struct rtentry));
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = 0;
if (inet_aton(gateway, &sin->sin_addr) < 0)
{
printf("inet_aton gateway error\n");
return -6;
}
memcpy(&rt.rt_gateway, sin, sizeof(struct sockaddr_in));
((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
rt.rt_flags = RTF_GATEWAY;
if (ioctl(fd, SIOCADDRT, &rt) < 0)
{
perror("ioctl(SIOCADDRT) error in set_default_route\n");
close(fd);
return -7;
}
close(fd);
#endif
return 0;
}
int GetIfAddr(char *ifname, char *Ipaddr, char *mask, char *gateway)
{
int fd;
int rc;
int ret;
int i=0;
#ifndef _WINDOWS_
struct ifreq ifr;
struct sockaddr_in sin;
struct sockaddr_in* p_sin=0;
struct rtentry rt;
fd = socket(AF_INET, SOCK_DGRAM, 0);//internet协议族的数据报类型套接口
if (fd < 0)
{
perror("socket error");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ifname);//将设备名作为输入参数传入
p_sin = (struct sockaddr_in*)&ifr.ifr_addr;
p_sin->sin_family = AF_INET;
ret = ioctl(fd, SIOCGIFHWADDR, &ifr); //执行取MAC地址操作
if (ret < 0)
{
close(fd);
perror("ioctl SIOCGIFHWADDR error");
return -2;
}
{
memcpy(m_LocalMacAddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); //取输出的MAC地址
for (i = 0; i < ETH_ALEN; i++) {
sprintf(m_szLocalMac, "%s%02x", m_szLocalMac, m_LocalMacAddr[i] & 0xff);
if (i != ETH_ALEN - 1) {
sprintf(m_szLocalMac, "%s:", m_szLocalMac);
}
}
printf("MacAddr is :%s\n", m_szLocalMac);
}
//get the broadcast addr
/* 获取当前网卡的广播地址 */
if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
{
close(fd);
return -3;
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
m_dwBroadcast = sin.sin_addr.s_addr;
printf("broadcast is :%s\n", inet_ntoa(sin.sin_addr));
//get the ip addr
/* 获取当前网卡的IP地址 */
if (ioctl(fd, SIOCGIFADDR, &ifr) < 0)
{
close(fd);
return -4;
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
uint32 dwLocalIp = sin.sin_addr.s_addr;
sprintf(m_szLocalIp,"%s", inet_ntoa(sin.sin_addr));
printf("LocalIp is :%s(%x)\n", inet_ntoa(sin.sin_addr),dwLocalIp);
/* 获取当前网卡的子网掩码 */
if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
{
close(fd);
return -5;
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
sprintf(m_szLocalMask, "%s", inet_ntoa(sin.sin_addr));
printf("LocalMask is :%s\n", inet_ntoa(sin.sin_addr));
/* 获取当前网卡的gateway */
//if (ioctl(fd, SIOCGADDRT, &ifr) < 0)
//{
// close(fd);
// return -5;
//}
//memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
sin.sin_addr.s_addr = (dwLocalIp&0x00FFFFFF)|0xFE000000;
sprintf(m_szLocalGateway, "%s", inet_ntoa(sin.sin_addr));
printf("LocalGateway is :%s\n", inet_ntoa(sin.sin_addr));
close(fd);
#else
#endif
return 0;
}
int addRoute(char *ipAddr, char *mask,char *gateWay,char* devName)
{
int fd;
int rc = 0;
#ifndef _WINDOWS_
struct sockaddr_in _sin;
struct sockaddr_in *sin = &_sin;
struct rtentry rt;
do
{
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0)
{
printf("addRoute: socket error\n");
rc = -1;
break;
}
//网关
memset(&rt, 0, sizeof(struct rtentry));
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = 0;
if(inet_aton(gateWay, &sin->sin_addr)<0)
{
printf( "addRoute: gateWay inet_aton error\n" );
rc = -2;
break;
}
memcpy ( &rt.rt_gateway, sin, sizeof(struct sockaddr_in));
((struct sockaddr_in *)&rt.rt_dst)->sin_family=AF_INET;
if(inet_aton(ipAddr, &((struct sockaddr_in *)&rt.rt_dst)->sin_addr)<0)
{
printf( "addRoute: dst inet_aton error\n" );
rc = -3;
break;
}
((struct sockaddr_in *)&rt.rt_genmask)->sin_family=AF_INET;
if(inet_aton(mask, &((struct sockaddr_in *)&rt.rt_genmask)->sin_addr)<0)
{
printf( "addRoute: mask inet_aton error\n" );
rc = -4;
break;
}
if(devName)
rt.rt_dev = devName;
rt.rt_flags = RTF_GATEWAY;
if (ioctl(fd, SIOCADDRT, &rt)<0)
{
printf( "ioctl(SIOCADDRT) error in set_route\n");
rc = -5;
}
}while(0);
close(fd);
#endif//_WINDOWS_
return rc;
}