Socket.h
#ifndef __SOCKET_H__
#define __SOCKET_H__
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable : 4786)
#include <errno.h>
#include <vector>
using namespace std;
// select mode
#define SELECT_MODE_READY 0x001
#define SELECT_MODE_WRITE 0x002
// select return codes
#define SELECT_STATE_READY 0
#define SELECT_STATE_ERROR 1
#define SELECT_STATE_ABORTED 2
#define SELECT_STATE_TIMEOUT 3
class Socket
{
public:
Socket(UINT mtu = 1500);
virtual ~Socket();
virtual void Close();
virtual int Write(PBYTE pBuffer, int writeSize, UINT nTimeOut = 500000); // 0.5sec
virtual int Read(BYTE* pBuffer, int readSize, UINT nTimeOut = 500000); // 0.5sec
virtual SOCKADDR_IN GetBindAddr();
virtual SOCKADDR_IN GetConnectAddr();
virtual UINT GetMTU();
static BOOL GetLocalIPList(vector<string>& vIPList);
static BOOL GetAdapterSpeed(vector<int>& vList);
protected:
void ReportError();
int Select(int mode, int timeoutUsec);
BOOL m_isOpen;
SOCKET m_Socket;
SOCKADDR_IN m_BindAddr;
SOCKADDR_IN m_ConnectAddr;
UINT m_Mtu;
};
#endif //__SOCKET_H__
Socket.cpp
#include "stdafx.h"
#include "Socket.h"
Socket::Socket(UINT mtu)
:m_Mtu(mtu)
{
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD( 2, 2 );
WSAStartup(wVersionRequested, &wsaData);
m_Socket = NULL;
memset(&m_BindAddr, 0, sizeof(m_BindAddr));
memset(&m_ConnectAddr, 0, sizeof(m_ConnectAddr));
m_isOpen = FALSE;
}
Socket::~Socket()
{
Close();
WSACleanup();
}
void Socket::Close()
{
if (m_Socket)
closesocket(m_Socket);
m_Socket = NULL;
m_isOpen = FALSE;
}
int Socket::Read(BYTE* pBuffer, int readSize, UINT nTimeOut)
{
int selectState;
int recvSize;
if (!pBuffer || !m_isOpen)
return -1;
selectState = Select(SELECT_MODE_READY, nTimeOut);
if (SELECT_STATE_TIMEOUT == selectState)
return 0;
if (SELECT_STATE_READY == selectState)
{
recvSize = recv(m_Socket, (char*)pBuffer, readSize, 0);
if (recvSize <= 0)
return -1;
return recvSize;
}
return -1;
}
int Socket::Write(PBYTE pBuffer, int writeSize, UINT nTimeOut)
{
int selectState = 0;
int sendSize = 0;
if (!pBuffer || !m_isOpen)
return -1;
selectState = Select(SELECT_MODE_WRITE, nTimeOut);
if (selectState == SELECT_STATE_TIMEOUT)
return 0;
if (selectState == SELECT_STATE_READY)
{
sendSize = send(m_Socket, (char*)pBuffer, writeSize, 0);
if (sendSize <= 0)
return -1;
return sendSize;
}
return -1;
}
SOCKADDR_IN Socket::GetBindAddr()
{
return m_BindAddr;
}
SOCKADDR_IN Socket::GetConnectAddr()
{
return m_ConnectAddr;
}
UINT Socket::GetMTU()
{
return m_Mtu;
}
// Waits for a file descriptor/socket to change status.
//
// network input plugins should use this function in order to
// not freeze the engine.
//
// params :
// mode SELECT_MODE_READY, SELECT_MODE_WRITE
// timeout_usec timeout in microsecond
//
// return value :
// SELECT_STATE_READY the file descriptor is ready for cmd
// SELECT_STATE_ERROR an i/o error occured
// SELECT_STATE_ABORTED command aborted by an other thread
// SELECT_STATE_TIMEOUT the file descriptor is not ready after timeout_usec microsecond
int Socket::Select(int mode, int timeoutUsec)
{
fd_set fdset;
fd_set *readSet, *writeSet;
timeval selectTimeout;
int ret;
selectTimeout.tv_sec = 0;
selectTimeout.tv_usec = timeoutUsec;
FD_ZERO (&fdset);
FD_SET (m_Socket, &fdset);
readSet = (mode & SELECT_MODE_READY) ? &fdset : NULL;
writeSet = (mode & SELECT_MODE_WRITE) ? &fdset : NULL;
ret = select ( (int)m_Socket + 1, readSet, writeSet, NULL, &selectTimeout);
if (ret == 1)
return SELECT_STATE_READY;
if (ret == SOCKET_ERROR)
{
if ( errno == EINTR)
return SELECT_STATE_ABORTED;
ReportError();
return SELECT_STATE_ERROR;
}
return SELECT_STATE_TIMEOUT;
}
void Socket::ReportError()
{
int isErr = WSAGetLastError();
printf("Socket error is:%d\n", isErr);
//Close();
}
BOOL Socket::GetLocalIPList(vector<string>& vIPList)
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
printf("GetLocalIPList : WSAStartup failed !");
return FALSE;
}
char szhn[256];
int nStatus = gethostname(szhn, sizeof(szhn));
if (nStatus == SOCKET_ERROR )
{
printf("Socket : Gethostname failed, Error code: %d", WSAGetLastError());
return FALSE;
}
HOSTENT *host = gethostbyname(szhn);
if (host != NULL)
{
for ( int i=0; ; i++ )
{
vIPList.push_back( inet_ntoa( *(IN_ADDR*)host->h_addr_list[i] ) ) ;
if ( host->h_addr_list[i] + host->h_length >= host->h_name )
break;
}
}
WSACleanup();
return TRUE;
}
Udp.h
#ifndef __UDP_H__
#define __UDP_H__
#include "Socket.h"
#include <WS2tcpip.h>
#include <string>
using namespace std;
class Udp : public Socket
{
public:
Udp(UINT mtu = 1500);
virtual ~Udp();
virtual BOOL Open(string bindIp = "", int bindPort = 0);
virtual BOOL Connect(string connectIp, int connectPort);
virtual int Read(BYTE* pBuffer, UINT16 bufferSize, UINT nTimeOut = 500000);
virtual int Write(PBYTE pBuffer, UINT16 bufferSize, UINT nTimeOut = 500000);
protected:
BOOL SetMulticast(PCSTR textIP);
BOOL m_isConnect;
};
#endif //__UDP_H__
#include "stdafx.h"
#include "Udp.h"
Udp::Udp(UINT mtu) :Socket(mtu)
{
m_isConnect = FALSE;
}
Udp::~Udp()
{
}
BOOL Udp::Open(string bindIp, int bindPort)
{
if (m_isOpen)
return FALSE;
m_isOpen = FALSE;
m_isConnect = FALSE;
int error = 0;
int i_val = 0;
if (m_Socket)
closesocket(m_Socket);
m_Socket= socket(AF_INET, SOCK_DGRAM, 0);
if ( m_Socket == INVALID_SOCKET )
{
ReportError();
return FALSE;
}
i_val = 0; // 非阻塞方式
error = ioctlsocket(m_Socket, FIONBIO, (ULONG*)&i_val);
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
i_val = (int)(1024 * 1024 * 1.25);//2M Byte 1000Mbps的network在0.01秒内最高可以接收到1.25MB数据
error = setsockopt( m_Socket, SOL_SOCKET, SO_RCVBUF, (char*)&i_val, sizeof(i_val) );
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
error = setsockopt( m_Socket, SOL_SOCKET, SO_SNDBUF, (char*)&i_val, sizeof(i_val) );
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
// 可重用
i_val = 1;
error = setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, (char*)&i_val, sizeof(i_val));
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
// 设置ttl
i_val = 5;
error = setsockopt(m_Socket,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&i_val, sizeof(i_val));
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
// 绑定套接字
memset((PVOID)&m_BindAddr, 0, sizeof(m_BindAddr));
m_BindAddr.sin_family = AF_INET;
m_BindAddr.sin_port = htons(bindPort);
m_BindAddr.sin_addr.s_addr = inet_addr(bindIp.c_str());
if ( IN_MULTICAST(ntohl(m_BindAddr.sin_addr.s_addr)) || m_BindAddr.sin_addr.s_addr == INADDR_BROADCAST )
m_BindAddr.sin_addr.s_addr = htonl(INADDR_ANY);
error = bind(m_Socket, (SOCKADDR*)&m_BindAddr, sizeof(m_BindAddr));
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
i_val = sizeof(m_BindAddr);
error = getsockname(m_Socket, (SOCKADDR*)&m_BindAddr, &i_val);
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
if ( ! SetMulticast(bindIp.c_str()))
return FALSE;
m_isOpen = TRUE;
return TRUE;
}
BOOL Udp::Connect(string connectIp, int connectPort)
{
if (!m_isOpen)
return FALSE;
int error = 0;
int i_val = 0;
memset((PVOID)&m_ConnectAddr, 0, sizeof(m_ConnectAddr));
if ( ! SetMulticast(connectIp.c_str()))
return FALSE;
m_ConnectAddr.sin_family = AF_INET;
m_ConnectAddr.sin_port = htons(connectPort);
m_ConnectAddr.sin_addr.s_addr = inet_addr(connectIp.c_str());
if (connect(m_Socket, (SOCKADDR*)&m_ConnectAddr, sizeof(m_ConnectAddr)) == SOCKET_ERROR )
{
ReportError();
return FALSE;
}
m_isConnect = TRUE;
return TRUE;
}
int Udp::Read(BYTE* pBuffer, UINT16 bufferSize, UINT nTimeOut)
{
int iRead;
if ( !m_isOpen )
return -1;
iRead = Socket::Read(pBuffer, bufferSize, nTimeOut);
return iRead;
}
int Udp::Write(PBYTE pBuffer, UINT16 bufferSize, UINT nTimeOut)
{
int iWrite;
if ( !m_isOpen || !m_isConnect)
return -1;
iWrite = Socket::Write(pBuffer, bufferSize, nTimeOut);
return iWrite;
}
BOOL Udp::SetMulticast(PCSTR textIP)
{
int error = 0;
int i_val = 0;
// 设置多播和广播
if ( IN_MULTICAST(ntohl(inet_addr(textIP))) )
{
i_val = 1;
error = setsockopt(m_Socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&i_val, sizeof(i_val) );
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
ip_mreq multicastAddr;
multicastAddr.imr_multiaddr.s_addr = inet_addr(textIP);
multicastAddr.imr_interface.s_addr = htonl(INADDR_ANY);
error = setsockopt(m_Socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicastAddr, sizeof(multicastAddr));
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
}
//设置广播
if ( inet_addr(textIP) == INADDR_BROADCAST )
{
i_val = 1;
error = setsockopt( m_Socket, SOL_SOCKET, SO_BROADCAST, (char*)&i_val, sizeof(i_val) );
if (error == SOCKET_ERROR)
{
ReportError();
return FALSE;
}
}
return TRUE;}
main.cpp
#include "Udp.h"
#include <process.h>
#include <iostream>
UINT CALLBACK RecvData(LPVOID arg)
{
Udp recv;
if(FALSE == recv.Open("192.168.1.10",2017))
{
std::cout << "Can not open Udp" << std::endl;
return 0;
}
char dataBuf[100];
while(1)
{
memset(dataBuf,'\0',100);
PBYTE pTemp = (PBYTE)dataBuf;
int nLen = sizeof(dataBuf);
int nRead = -1;
while(nLen > 0)
{
nRead = recv.Read(pTemp,nLen,1000000);
if(nRead == SOCKET_ERROR || nRead == 0) break;
pTemp += nRead;
nLen -= nRead;
}
if(nLen == 0)
{
//
std::cout << "GetData: " << dataBuf << std::endl;
}
}
return 0;
}
int main()
{
UINT tid;
HANDLE hThread = (HANDLE)_beginthreadex(NULL,0,RecvData,NULL,0,&tid);
Udp send;
send.Open();
if(FALSE == send.Connect("192.168.1.10",2017))
std::cout << "Can not connect Udp" << std::endl;
char* dataBuf = "abcdefghijklmnopqrstuvwxyz";
PBYTE pTemp = (PBYTE)dataBuf;
int nLen = strlen(dataBuf);
int nWrite = -1;
while(nLen > 0)
{
nWrite = send.Write(pTemp,nLen);
if(nWrite == SOCKET_ERROR || nWrite == 0) break;
pTemp += nWrite;
nLen -= nWrite;
}
system("pause");
CloseHandle(hThread);
return 0;
}