From 32f9acc866697b12b567ed6b1150f0d9efeb3573 Mon Sep 17 00:00:00 2001 From: TAO Cheng Date: Wed, 29 Oct 2014 21:05:58 +0800 Subject: [PATCH] get host ip address. --- .../Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.cpp | 281 +++++++++++++++--- .../Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.h | 37 ++- .../Hsi/Tools/UsbUtility/UsbUtil/Mv_Util.rc | 6 +- .../Tools/UsbUtility/UsbUtil/So7_Option.cpp | 4 +- .../UsbUtility/UsbUtil/So7_Util_PLC_TCPIP.cpp | 24 +- .../Hsi/Tools/UsbUtility/UsbUtil/resource.h | 2 + .../Hsi/Tools/UsbUtility/UsbUtil_VS2010.suo | Bin 150016 -> 150016 bytes 7 files changed, 283 insertions(+), 71 deletions(-) diff --git a/PcDmis/Base/Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.cpp b/PcDmis/Base/Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.cpp index 314f30c..6e6867e 100644 --- a/PcDmis/Base/Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.cpp +++ b/PcDmis/Base/Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.cpp @@ -8,21 +8,39 @@ const int WSA_MINOR_VERSION = 1; #define WSA_VERSION MAKEWORD(WSA_MAJOR_VERSION, WSA_MINOR_VERSION) #define SOCKADDR_LEN sizeof(SOCKADDR_IN) +int CSo7_TCPIP::m_iReceiveMaxBufSize=1024; +int CSo7_TCPIP::m_iSendMaxBufSize=1024; + +SOCKET CSo7_TCPIP::m_Socket=INVALID_SOCKET; +in_addr CSo7_TCPIP::m_SreverIPAddress; +u_short CSo7_TCPIP::m_iServerPortNumber=static_cast(0); //================================================================ CSo7_TCPIP::CSo7_TCPIP() { - m_socket=INVALID_SOCKET; - m_pszNetworkAddr="127.0.0.1"; - m_nPortNumber=8000; - m_bDisableTimeout=false; + m_hMsgWnd=NULL; + m_ReceiveBuf=NULL; + m_SendBuf=NULL; + + m_iBytesToReceive = 0; + m_iBytesReceived = 0; + m_iBytesToSend = 0; + m_iBytesSent = 0; + m_ReceiveBuf = new char[m_iReceiveMaxBufSize]; + m_SendBuf = new char[m_iSendMaxBufSize]; } //================================================================ CSo7_TCPIP::~CSo7_TCPIP() { - //DisConnect(); + DisConnect(); + if(m_SendBuf) + delete [] m_SendBuf; + m_SendBuf=NULL; + if(m_ReceiveBuf) + delete [] m_ReceiveBuf; + m_ReceiveBuf=NULL; } //================================================================ int CSo7_TCPIP::Init_Winsock() @@ -41,11 +59,13 @@ int CSo7_TCPIP::Init_Winsock() } return TRUE; } + //================================================================ -TCPIP_RETURN_CODE CSo7_TCPIP::Connect() +TCPIP_RETURN_CODE CSo7_TCPIP::Connect(const HWND& _hWnd,const in_addr& _IPAddress,const u_short& _nPortNumber) { TCPIP_RETURN_CODE rCode=TCPIP_CONNECT_OK; - //DisConnect(); + m_hMsgWnd=_hWnd; + m_iServerPortNumber=_nPortNumber; int retVal(0), errorCode(0); retVal=Init_Winsock(); if(!retVal) @@ -53,42 +73,23 @@ TCPIP_RETURN_CODE CSo7_TCPIP::Connect() return TCPIP_INIT_WINSOCK_ERROR; } // 创建套节字 - m_socket = socket(AF_INET, SOCK_STREAM, 0); - if(m_socket == INVALID_SOCKET) + m_Socket = socket(AF_INET, SOCK_STREAM, 0); + if(m_Socket == INVALID_SOCKET) { rCode=TCPIP_INVAILD_SOCKET; } else { // 设置socket为窗口通知消息类型 - ::WSAAsyncSelect(m_socket, m_hMsgWnd, - WM_SOCKET, FD_CONNECT | FD_CLOSE | FD_WRITE | FD_READ); - - // 假定szAddr是IP地址 - ULONG uAddr = inet_addr(m_pszNetworkAddr); - if(uAddr == INADDR_NONE) - { - // 不是IP地址,就认为这是主机名称 - // 从主机名取得IP地址 - hostent* pHost = ::gethostbyname(m_pszNetworkAddr); - if(pHost == NULL) - { - closesocket(m_socket); - m_socket = INVALID_SOCKET; - return TCPIP_INVAILD_SOCKET; - } - // 得到以网络字节顺序排列的IP地址 - uAddr = ((struct in_addr*)*(pHost->h_addr_list))->s_addr; - } + ::WSAAsyncSelect(m_Socket, m_hMsgWnd,WM_SOCKET, FD_CONNECT | FD_CLOSE | FD_WRITE | FD_READ); // 填写服务器地址信息 sockaddr_in remote; - remote.sin_addr.S_un.S_addr = uAddr; + remote.sin_addr = _IPAddress; remote.sin_family = AF_INET; - remote.sin_port = htons(m_nPortNumber); - + remote.sin_port = htons(m_iServerPortNumber); // 连接到远程机 - retVal=connect(m_socket, (sockaddr*)&remote, sizeof(sockaddr)); + retVal=connect(m_Socket, (sockaddr*)&remote, sizeof(sockaddr)); if(retVal) { errorCode = WSAGetLastError(); @@ -100,33 +101,82 @@ TCPIP_RETURN_CODE CSo7_TCPIP::Connect() //================================================================ TCPIP_RETURN_CODE CSo7_TCPIP::DisConnect() { - if(m_socket == INVALID_SOCKET) + if(m_Socket == INVALID_SOCKET) { return TCPIP_INVAILD_SOCKET; } - ::closesocket(m_socket); - m_socket = INVALID_SOCKET; + ::closesocket(m_Socket); + m_Socket = INVALID_SOCKET; return TCPIP_CONNECT_OK; } //================================================================ -TCPIP_RETURN_CODE CSo7_TCPIP::Send() +TCPIP_RETURN_CODE CSo7_TCPIP::GetHostIPAddr(in_addr& _IPAddress) { - if(m_socket == INVALID_SOCKET) + if(m_Socket == INVALID_SOCKET) { return TCPIP_INVAILD_SOCKET; } - BYTE bSendData[20]={1,2,3,4,5}; - int iSendDataLength=20; - if(::send(m_socket,(const char*)(bSendData),iSendDataLength,0) != -1) - { - return TCPIP_CONNECT_OK; - } + char HostName[100]; + gethostname(HostName,sizeof(HostName)); + hostent *pAddr; + pAddr=gethostbyname(HostName); + memcpy(&_IPAddress,pAddr->h_addr_list[0],sizeof(in_addr)); return TCPIP_CONNECT_OK; } //================================================================ -TCPIP_RETURN_CODE CSo7_TCPIP::Recv() +TCPIP_RETURN_CODE CSo7_TCPIP::Send(int _Addr,int _Data) { - if(m_socket == INVALID_SOCKET) + _Addr=0; + _Data=0; + if(m_Socket == INVALID_SOCKET) + { + return TCPIP_INVAILD_SOCKET; + } + int i, errorCode, numBytesSent; + unsigned long numDataBytes; + SOCKET s = m_Socket; + m_iBytesSent = 0; + m_iBytesToSend = sizeof(unsigned long) + 1; + numDataBytes = htonl(m_iBytesToSend); + for(i=0;i=m_iBytesToSend) + { + m_iBytesToSend = 0; + m_iBytesSent = 0; + break; + } + } + + return TCPIP_CONNECT_OK; +} +//================================================================ +TCPIP_RETURN_CODE CSo7_TCPIP::Recv(int _Addr,int& _Data,bool _bWait) +{ + _Addr=0; + _Data=0; + _bWait=false; + if(m_Socket == INVALID_SOCKET) { return TCPIP_INVAILD_SOCKET; } @@ -152,18 +202,151 @@ LRESULT CSo7_TCPIP::OnSocket(WPARAM wParam, LPARAM lParam) break; case FD_READ: { - char szText[1024] = { 0 }; - ::recv(s, szText, 1024, 0); - Recv(); + m_ProcessSocketReadEvent(s); } break; case FD_WRITE: //This event happens when the tcp buffers are ready for another send. //So if there is not enough room for the first write the event will happen //and then the buffers are ready for more. + m_ProcessSocketWriteEvent(); break; case FD_CLOSE: break; } return 0; -} \ No newline at end of file +} +//================================================================ +void CSo7_TCPIP::clearSendBuf(void) +{ + int i; + for(i=0;i=m_iBytesToSend) + { + m_iBytesSent = 0; + clearSendBuf(); + break; + } + } +} +//================================================================ +void CSo7_TCPIP::m_ProcessSocketReadEvent(SOCKET s) +{ + int bytesReceived=0; + int headerSize = sizeof(unsigned long) + sizeof(char); + int errorCode; + if(true) + { + unsigned long *numBytesPtr; + bytesReceived = recv(s, &(m_ReceiveBuf[m_iBytesReceived]), headerSize-m_iBytesReceived, 0); + if(bytesReceived == SOCKET_ERROR) + { + errorCode = WSAGetLastError(); + if (errorCode == WSAEWOULDBLOCK) + { + //have to wait for the next receive event + return; + } + else + { + //showSocketError(errorCode); + return; + } + } + m_iBytesReceived += bytesReceived; + if(m_iBytesReceived < sizeof(unsigned long) + sizeof(char)) + {//like this will ever happen... Have to wait for the next receive event + return; + } + numBytesPtr = (unsigned long*) &(m_ReceiveBuf[0]); + m_iBytesToReceive = ntohl(*numBytesPtr); + m_iBytesReceived = 0; + + //allocate memory for the character or the double array + if(true) + { + if(m_dReceiveDBuf) + {//clean memory because returning + delete [] m_dReceiveDBuf; + m_dReceiveDBuf = NULL; + } + m_iReceiveDBufSize = m_iBytesToReceive/(sizeof(double)); + m_dReceiveDBuf = new double[m_iReceiveDBufSize]; + memset (m_dReceiveDBuf,m_iReceiveDBufSize*sizeof(double),0); // PR#254048 + } + } + + //The header has been received. Now we need to get the data + if(true) + { + bytesReceived = recv(s, &(((char*)m_dReceiveDBuf)[m_iBytesReceived]), + m_iBytesToReceive - m_iBytesReceived, 0); + } + if(bytesReceived == SOCKET_ERROR) + { + errorCode = WSAGetLastError(); + + if (errorCode == WSAEWOULDBLOCK) + {//have to wait for the next receive event + return; + } + else + { + if(m_dReceiveDBuf) + {//clean memory because returning + delete [] m_dReceiveDBuf; + m_dReceiveDBuf = NULL; + m_iReceiveDBufSize = 0; + } + //showSocketError(errorCode); + return; + } + } + m_iBytesReceived += bytesReceived; + if(m_iBytesReceived >= m_iBytesToReceive) + { + //we are done, reset the variables for next data and clean up + m_iBytesReceived = 0; + m_iBytesToReceive = 0; + if(m_dReceiveDBuf) + { + delete [] m_dReceiveDBuf; + m_dReceiveDBuf = NULL; + m_iReceiveDBufSize = 0; + } + } +} diff --git a/PcDmis/Base/Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.h b/PcDmis/Base/Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.h index c2d16f7..1b3e57c 100644 --- a/PcDmis/Base/Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.h +++ b/PcDmis/Base/Interfac/Msi/Hsi/SevenOcean/So7_TCPIP.h @@ -1,5 +1,3 @@ -// protocol for control SevenOcean's Machine -// ////////////////////////////////////////////////////////////////////// #ifndef SO7_TCPIP_H_INCLUDED_ #define SO7_TCPIP_H_INCLUDED_ @@ -31,18 +29,35 @@ public: CSo7_TCPIP(); virtual ~CSo7_TCPIP(); - TCPIP_RETURN_CODE Connect(); - TCPIP_RETURN_CODE Send(); - TCPIP_RETURN_CODE Recv(); + TCPIP_RETURN_CODE Connect(const HWND& _hWnd,const in_addr& _IPAddress,const u_short& _nPortNumber); + TCPIP_RETURN_CODE Send(int _Addr,int _Data); + TCPIP_RETURN_CODE Recv(int _Addr,int& _Data,bool _bWait); TCPIP_RETURN_CODE DisConnect(); - HWND m_hMsgWnd; + TCPIP_RETURN_CODE GetHostIPAddr(in_addr& _IPAddress); + + LRESULT OnSocket(WPARAM wParam, LPARAM lParam); private: - SOCKET m_socket; - LPCSTR m_pszNetworkAddr; - u_short m_nPortNumber; - bool m_bDisableTimeout; - int Init_Winsock(); + HWND m_hMsgWnd; + + char *m_ReceiveBuf; + char *m_SendBuf; + double *m_dReceiveDBuf; + int m_iReceiveDBufSize; + int m_iBytesToReceive,m_iBytesReceived; + int m_iBytesToSend,m_iBytesSent; + static int m_iReceiveMaxBufSize; + static int m_iSendMaxBufSize; + + static SOCKET m_Socket; + static in_addr m_SreverIPAddress; + static u_short m_iServerPortNumber; + + void clearSendBuf(); + + int Init_Winsock(); + void m_ProcessSocketWriteEvent(); + void m_ProcessSocketReadEvent(SOCKET s); }; #endif diff --git a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/Mv_Util.rc b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/Mv_Util.rc index 0315741..9e4f3b7 100644 --- a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/Mv_Util.rc +++ b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/Mv_Util.rc @@ -1050,8 +1050,10 @@ BEGIN PUSHBUTTON "Read Data",IDC_BUTTON_PLC_TCPIP_READ,203,30,63,18 PUSHBUTTON "Write Data",IDC_BUTTON_PLC_TCPIP_WRITE,203,62,63,18 GROUPBOX "TCP/IP Control",IDC_STATIC,110,12,174,81 - EDITTEXT IDC_EDIT_PLC_TCPIP_ADDR,139,47,40,14,ES_AUTOHSCROLL - LTEXT "Addr",IDC_STATIC,116,50,16,8 + EDITTEXT IDC_EDIT_PLC_TCPIP_ADDR,141,32,40,14,ES_AUTOHSCROLL + LTEXT "Addr",IDC_STATIC,116,35,16,8 + EDITTEXT IDC_EDIT_PLC_TCPIP_Data,141,61,40,14,ES_AUTOHSCROLL + LTEXT "Data",IDC_STATIC,116,64,16,8 END diff --git a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/So7_Option.cpp b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/So7_Option.cpp index 211ae14..fb9ad8c 100644 --- a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/So7_Option.cpp +++ b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/So7_Option.cpp @@ -140,13 +140,13 @@ BOOL CSo7_Option::OnInitDialog() ((CButton *)GetDlgItem(IDC_RADIO_VIDEOCARD_TC4000))->SetCheck(FALSE); ((CButton *)GetDlgItem(IDC_RADIO_VIDEOCARD_MV900))->SetCheck(FALSE); ((CButton *)GetDlgItem(IDC_RADIO_SO7_IP_CAMERA))->SetCheck(FALSE); - ((CButton *)GetDlgItem(IDC_RADIO_CONTROLLER))->SetCheck(TRUE); + ((CButton *)GetDlgItem(IDC_RADIO_CONTROLLER))->SetCheck(FALSE); ((CButton *)GetDlgItem(IDC_RADIO__SO7_RS232))->SetCheck(FALSE); ((CButton *)GetDlgItem(IDC_RADIO_KEYENCE_LASER))->SetCheck(FALSE); ((CButton *)GetDlgItem(IDC_RADIO_SO7_VERIFICATION_ALGORITHM))->SetCheck(FALSE); ((CButton *)GetDlgItem(IDC_RADIO_TEST_IMAGE_DLL))->SetCheck(FALSE); ((CButton *)GetDlgItem(IDC_RADIO_ART_PCI8622))->SetCheck(FALSE); - ((CButton *)GetDlgItem(IDC_RADIO_SO7_OMRON_PLC))->SetCheck(FALSE); + ((CButton *)GetDlgItem(IDC_RADIO_SO7_OMRON_PLC))->SetCheck(TRUE); #ifdef _RELEASE_SO7_CONTROLER_ONLY ((CButton *)GetDlgItem(IDC_RADIO_VIDEOCARD_SDK3000))->EnableWindow(FALSE); diff --git a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/So7_Util_PLC_TCPIP.cpp b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/So7_Util_PLC_TCPIP.cpp index 070e23e..c258f32 100644 --- a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/So7_Util_PLC_TCPIP.cpp +++ b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/So7_Util_PLC_TCPIP.cpp @@ -48,9 +48,15 @@ END_MESSAGE_MAP() void CSo7_Util_PLC_TCPIP::OnBnClickedButtonPlcTcpipConnect() { - g_pSo7_TCPIP->m_hMsgWnd=m_hWnd; - TCPIP_RETURN_CODE rCode=g_pSo7_TCPIP->Connect(); - m_csMSG.Format(_T("Connect return code:%d."),rCode); + in_addr IPAddress; + IPAddress.S_un.S_addr=inet_addr("192.168.0.5"); + TCPIP_RETURN_CODE rCode=g_pSo7_TCPIP->Connect(m_hWnd,IPAddress,9600); + m_csMSG.Format(_T("Server:192.168.0.5[9600] Connect return code:%d."),rCode); + OutputWithScroll(m_csMSG,m_edMSG); + rCode=g_pSo7_TCPIP->GetHostIPAddr(IPAddress); + m_csMSG.Format(_T("Client:%d.%d.%d.%d return code:%d."), + IPAddress.S_un.S_un_b.s_b1,IPAddress.S_un.S_un_b.s_b2, + IPAddress.S_un.S_un_b.s_b3,IPAddress.S_un.S_un_b.s_b4,rCode); OutputWithScroll(m_csMSG,m_edMSG); } @@ -58,7 +64,7 @@ void CSo7_Util_PLC_TCPIP::OnBnClickedButtonPlcTcpipConnect() void CSo7_Util_PLC_TCPIP::OnBnClickedButtonPlcTcpipDisconnect() { TCPIP_RETURN_CODE rCode=g_pSo7_TCPIP->DisConnect(); - m_csMSG.Format(_T("Connect return code:%d."),rCode); + m_csMSG.Format(_T("DisConnect return code:%d."),rCode); OutputWithScroll(m_csMSG,m_edMSG); } @@ -71,9 +77,9 @@ void CSo7_Util_PLC_TCPIP::OnBnClickedButtonPlcTcpipRead() void CSo7_Util_PLC_TCPIP::OnBnClickedButtonPlcTcpipWrite() { - TCPIP_RETURN_CODE rCode=g_pSo7_TCPIP->Send(); - m_csMSG.Format(_T("Connect return code:%d."),rCode); - OutputWithScroll(m_csMSG,m_edMSG); + //TCPIP_RETURN_CODE rCode=g_pSo7_TCPIP->Send(1001,0); + //m_csMSG.Format(_T("Connect return code:%d."),rCode); + //OutputWithScroll(m_csMSG,m_edMSG); } @@ -113,7 +119,11 @@ void CSo7_Util_PLC_TCPIP::OutputWithScroll(const CString &strNewText,CEdit &edtO LRESULT CSo7_Util_PLC_TCPIP::OnSocket(WPARAM w, LPARAM p) { LRESULT lResult=0; + UNREFERENCED_PARAMETER(w); + UNREFERENCED_PARAMETER(p); + /* if( g_pSo7_TCPIP ) lResult = g_pSo7_TCPIP->OnSocket(w,p); + */ return( lResult ); } \ No newline at end of file diff --git a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/resource.h b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/resource.h index 2142f40..38cd0bd 100644 --- a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/resource.h +++ b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil/resource.h @@ -1053,6 +1053,8 @@ #define IDC_BUTTON_PLC_TCPIP_WRITE 1886 #define IDC_EDIT_PLC_TCPIP_ADDR 1887 #define IDC_EDIT_MSG 1888 +#define IDC_EDIT_PLC_TCPIP_ADDR2 1889 +#define IDC_EDIT_PLC_TCPIP_Data 1889 #define IDC_BUTTON_DIY_EXIT_BUTTON 32740 #define ID_EDIT_SO7_CONFIG_MOTION 32741 diff --git a/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil_VS2010.suo b/PcDmis/Base/Interfac/Msi/Hsi/Tools/UsbUtility/UsbUtil_VS2010.suo index 701e583eeb8330eb295ac4151fa714b16a6eeaef..13dc108e3d068ae58f7c16d9c358224f178e0094 100644 GIT binary patch delta 4256 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