用select模式收发处理数据(跨平台)

来源:互联网 发布:天星教育php招聘 编辑:程序博客网 时间:2024/06/07 02:57

   本Demo程序模拟C/S传输数据。采用select模式,分别实现了一个客户端小程序和服务端小程序。已在VC2005和Fedroa 13下测试通过。因时间有限,功能简单,欢迎交流,学习!

 

main.cpp

#include "Sock.h"/*** 传输数据格式*  ___________ _____________* |           |             |* | 32字节头   | 负载数据     |* |___________|_____________|** 其中32位头中:* 第0个字节为数据包起始标志:0xCC* 第1个字节为命令字* 第4个字节为负载数据长度* 其余字节填0**/int main(int argc, char* argv[]){int nRet;Sock g_sock;char szBuf[1024];//初始化Socket环境nRet = g_sock.StartUp();if (nRet < 0){cout<<endl<<"main::init system error"<<endl;return 1;}//客户端#if defined(_CLIENT_)cout<<endl<<"please input s, to start send data : ";char ch;while (1){cin>>ch;if ( ch == 's'){break;}}g_sock.SetRemoteAddr(SERVER_IP, SERVER_PORT);if (opMode_udp == g_sock.GetProtocol()){//创建并绑定本端SocketnRet = g_sock.CreateSock(CLIENT_IP, CLIENT_PORT);if (nRet < 0){cout<<endl<<"main::CreateSock error"<<endl;return 1;}}else if (opMode_tcp == g_sock.GetProtocol()){//创建本端Socket,并连接服务端nRet = g_sock.StartConnect(CLIENT_IP, CLIENT_PORT, 5000);if (nRet < 0){cout<<endl<<"main::StartConnect error"<<endl;return 1;}}//向服务端发送登录请求memset(szBuf, 0, sizeof(szBuf));szBuf[0] = (char)0xCC;szBuf[1] = (char)0xA0;char *p = "Hello Server!";int nExtLen = strlen(p);memcpy(szBuf + 4, &nExtLen, sizeof(unsigned int));strcpy(szBuf + HEADER_SIZE, p);nRet = g_sock.SendData(szBuf, HEADER_SIZE + nExtLen);if (nRet < 0){cout<<endl<<"main::SendData error"<<endl;}else{cout<<endl<<"main::SendData ok"<<endl;}//接收来自服务端的请求回应,并处理nRet = g_sock.RecvData();//服务端#elif defined(_SERVER_)//创建本端套接字,绑定,并开始侦听nRet = g_sock.StartListen(SERVER_IP, SERVER_PORT);if (nRet < 0){cout<<endl<<"main::StartListen error"<<endl;return 1;}g_sock.SetRemoteAddr(CLIENT_IP, CLIENT_PORT);//接收来自客户端的请求,并进行应答处理nRet = g_sock.RecvData();#endif#ifdef WIN32system("pause");#endif//清理socket环境g_sock.CleanUp();return 0;}


 

sock.h

 

#ifndef _SOCK_H#define _SOCK_H#ifdef WIN32#ifndef _WIN32_WINNT#define _WIN32_WINNT 0x0400#endif#define    WIN32_LEAN_AND_MEAN#include <windows.h>#include <winsock2.h>#define EWOULDBLOCK             WSAEWOULDBLOCK#define EINPROGRESS             WSAEINPROGRESS#pragma warning(disable:4996)#else#include <string.h>#include <unistd.h>#include <errno.h>#include <limits.h>#include <stdarg.h>#include <time.h>#include <sys/stat.h>#include <sys/fcntl.h>#include <fcntl.h>#include <sys/types.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <ctype.h>#define EWOULDBLOCK EAGAIN#include <assert.h>#include <netinet/tcp.h>#include <semaphore.h>typedef int SOCKET;#define INVALID_SOCKET -1#define closesocket close #endif#include <iostream>using namespace std;typedef enum _opMode{opMode_none = 0,opMode_tcp,opMode_udp} opMode;#define HEADER_SIZE 32#define CLIENT_IP"127.0.0.1"#define SERVER_IP"127.0.0.1"#define CLIENT_PORT 5678#define SERVER_PORT 5679class Sock{public:Sock(void);~Sock(void);int SetRemoteAddr(const char* szIp, int nPort);int GetProtocol(){return m_nProtocol;}int StartUp();int CleanUp();int CreateSock(const char* szIp = NULL, int nPort = 0);int StartListen(const char* szIp, int nPort);int StartConnect(const char* szIp, int nPort, int nTimeOut);int SendData(char *pszbuf,int nLength);int RecvData();int TcpRecv();int UdpRecv();int DealData(char *pData, int nLength);private:unsigned long   m_localIp;unsigned shortm_localPort;unsigned longm_remoteIp;unsigned shortm_remotePort;intm_nProtocol;SOCKETm_socket;SOCKETm_clientSock;intm_recvBuffSize;intm_sendBuffSize;intm_bExitRecv;};#endif

Sock.cpp

#include "Sock.h"Sock::Sock(void){m_remoteIp= INADDR_ANY;m_remotePort= 0;m_localIp= INADDR_ANY;m_localPort= 0;m_socket = INVALID_SOCKET;m_clientSock = INVALID_SOCKET;m_recvBuffSize = 4 * 1024;m_sendBuffSize = 4 * 1024;m_bExitRecv = false;m_nProtocol = opMode_udp;}Sock::~Sock(void){}int Sock::SetRemoteAddr(const char* szIp, int nPort){m_remoteIp = inet_addr(szIp);m_remotePort = htons(nPort);return 1;}int Sock::StartUp(){#ifdef WIN32WSADATA wsa = {0};int ret = WSAStartup(MAKEWORD(2,2), &wsa);if (ret != 0){return -1;}#endifreturn 1;}int Sock::CleanUp(){#ifdef WIN32if (WSACleanup() == SOCKET_ERROR){return -1;}#endifreturn 1;}intSock::CreateSock(const char* szIp, int nPort){if (m_socket != INVALID_SOCKET){return -1;}//创建套接字if (opMode_tcp == m_nProtocol){m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);}else if (opMode_udp == m_nProtocol){m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);}#ifdef WIN32errno = WSAGetLastError();#endifif (m_socket == INVALID_SOCKET){return -1;}int nBlock = 1; //设为非阻塞模式int nRet;#ifdef WIN32nRet = ::ioctlsocket(m_socket,FIONBIO,(u_long FAR *)&nBlock);if (nRet == SOCKET_ERROR) {errno = ::WSAGetLastError();nRet = -1;}#elsenBlock = ::fcntl(m_socket, F_GETFL, 0);if (nBlock != -1){nBlock |= O_NONBLOCK;nRet = ::fcntl(m_socket, F_SETFL, nBlock);}#endifif ( -1 == nRet ){closesocket(m_socket); m_socket = INVALID_SOCKET;return -1;}if (szIp == NULL){m_localIp = INADDR_ANY;}else{m_localIp = inet_addr(szIp);}m_localPort = htons(nPort);//绑定套接字端口if (m_localPort != 0){struct sockaddr_in local_addr;memset(&local_addr, 0, sizeof(struct sockaddr_in));local_addr.sin_family = AF_INET;local_addr.sin_port = m_localPort;local_addr.sin_addr.s_addr = m_localIp;if (INVALID_SOCKET == bind(m_socket, (struct sockaddr *)&local_addr, sizeof(struct sockaddr))){closesocket(m_socket);m_socket = INVALID_SOCKET;return -1;}}else if (opMode_udp == m_nProtocol){//随机绑定struct sockaddr_in local_addr;memset(&local_addr, 0, sizeof(struct sockaddr_in));local_addr.sin_family = AF_INET;if ( '\0' == szIp[0] ){local_addr.sin_addr.s_addr = htonl(INADDR_ANY);}else{local_addr.sin_addr.s_addr = inet_addr(szIp);}int n;for (n = 0; n < 10000; n++){local_addr.sin_port = htons(nPort + n);if ( 0 == bind(m_socket, (struct sockaddr*)&local_addr, sizeof(local_addr)) ){break;}}if (10000 == n){closesocket(m_socket);m_socket = INVALID_SOCKET;return -1;}}//设置套接字接收和发送缓冲区大小if(m_recvBuffSize > 0)setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&m_recvBuffSize, sizeof(int));if(m_sendBuffSize > 0)setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&m_sendBuffSize, sizeof(int));return 1;}int Sock::StartListen(const char* szIp, int nPort){int nRet = CreateSock(szIp, nPort);if ( nRet < 0 ){return -1;}if (opMode_tcp == m_nProtocol){listen(m_socket,5);}return 1;}int Sock::StartConnect(const char* szIp, int nPort, int nTimeOut){int nRet = CreateSock(szIp, nPort);if (nRet < 0){return -1;}struct sockaddr_in remote_addr;memset(&remote_addr, 0, sizeof(remote_addr));remote_addr.sin_family = AF_INET;remote_addr.sin_addr.s_addr = m_remoteIp;remote_addr.sin_port = m_remotePort;//连接服务端nRet = connect(m_socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr));#ifdef WIN32if ( SOCKET_ERROR == nRet && (errno = WSAGetLastError()) == EWOULDBLOCK){#elseif ( -1 == nRet && EINPROGRESS == errno ){errno = EWOULDBLOCK; #endiffd_set fdwrite;FD_ZERO(&fdwrite);FD_SET(m_socket,&fdwrite);timeval tv;tv.tv_sec = nTimeOut/1000;tv.tv_usec = nTimeOut%1000;nRet = select(m_socket + 1, NULL, &fdwrite, NULL, &tv);#ifdef WIN32if ( SOCKET_ERROR == nRet ){errno = WSAGetLastError();closesocket(m_socket);m_socket = INVALID_SOCKET;return -1;}#elseif ( -1 == nRet ){closesocket(m_socket);m_socket = INVALID_SOCKET;    return -1;}#endifif ( 0 == nRet ) //超时{closesocket(m_socket);m_socket = INVALID_SOCKET;return -1;}}else{closesocket(m_socket);m_socket = INVALID_SOCKET;return -1;}return 1;}int Sock::SendData(char *pszbuf,int nLength){if (!pszbuf){return -1;}int nRet;if (opMode_tcp == m_nProtocol){#if defined(_CLIENT_)nRet = send(m_socket,pszbuf,nLength,0);#elif defined(_SERVER_)nRet = send(m_clientSock,pszbuf,nLength,0);#endif}else if (opMode_udp == m_nProtocol){sockaddr_in remote_addr;remote_addr.sin_family = AF_INET;remote_addr.sin_addr.s_addr = m_remoteIp;remote_addr.sin_port = m_remotePort;nRet = sendto(m_socket,pszbuf,nLength,0,(sockaddr*)&remote_addr,sizeof(remote_addr));}if (nRet != nLength){cout<<endl<<"Sock::SendData socket error.";return -1;}else{cout<<endl<<"Sock::SendData send data ok.";}return 1;}int Sock::RecvData(){int nRet;if (opMode_udp == m_nProtocol){nRet = UdpRecv();}else if (opMode_tcp == m_nProtocol){nRet = TcpRecv();}return 1;}int Sock::TcpRecv(){int fds,nRet;int nNeeRecvLen = 0,nRecvLen = 0, ntmpLen = 0;timeval tv;char szbuf[1024*4];int iTotal;fd_set fd_recv;FD_ZERO(&fd_recv);sockaddr_in addr;int iAddrSize = sizeof(addr);SOCKET tmpSock;while (true){if (m_bExitRecv){break;}tv.tv_sec = 0;tv.tv_usec = 100000;//memset(szbuf,0,sizeof(szbuf));fds = 0;FD_ZERO(&fd_recv);FD_SET(m_socket,&fd_recv);fds = m_socket;#ifdef _SERVER_if (INVALID_SOCKET != m_clientSock){FD_SET(m_clientSock,&fd_recv);if (m_clientSock > m_socket){fds = m_clientSock;}}#endifif ( fds <=0 ){#ifdef WIN32Sleep(1);#elsesleep(1);#endifcontinue;}iTotal = select(fds + 1, &fd_recv, 0, 0, &tv);#ifdef WIN32if ( SOCKET_ERROR == iTotal ){errno = WSAGetLastError();cout<<endl<<"Sock::TcpRecv socket error = "<<errno;}#elseif ( -1 == iTotal ){cout<<endl<<"Sock::TcpRecv socket error = "<<errno;}#endifif ( iTotal == 0 ) //超时{continue;}if (FD_ISSET(m_socket,&fd_recv) || FD_ISSET(m_clientSock,&fd_recv))//接收{#ifdef _SERVER_if (INVALID_SOCKET == m_clientSock){m_clientSock = accept(m_socket,(sockaddr*)&addr,#if !defined(WIN32)(socklen_t*)#endif&iAddrSize);if ( INVALID_SOCKET == m_clientSock ) //错误{#ifdef WIN32errno = WSAGetLastError();#endifcout<<endl<<"Sock::TcpRecv socket error = "<<errno;}else{int nRet;nRet = setsockopt(m_clientSock, SOL_SOCKET, SO_RCVBUF, (char*)&m_recvBuffSize, sizeof(m_recvBuffSize));nRet = setsockopt(m_clientSock, SOL_SOCKET, SO_SNDBUF, (char*)&m_sendBuffSize, sizeof(m_sendBuffSize));int nBlock = 1;#ifdef WIN32nRet = ::ioctlsocket(m_clientSock,FIONBIO,(u_long FAR *)&nBlock);if (nRet == SOCKET_ERROR) {errno = ::WSAGetLastError();nRet = -1;}#elsenBlock = ::fcntl(m_clientSock, F_GETFL, 0);if (nBlock != -1){nBlock |= O_NONBLOCK;nRet = ::fcntl(m_clientSock, F_SETFL, nBlock);}#endifif ( -1 == nRet ){cout<<endl<<"Sock::TcpRecv socket error = "<<errno;}}continue;}else{tmpSock = m_clientSock;}#elsetmpSock = m_socket;#endifif ( 0 == nNeeRecvLen ) //接收消息32位头{nNeeRecvLen = HEADER_SIZE;nRecvLen = recv(tmpSock, szbuf, nNeeRecvLen, 0);#ifdef WIN32if ( SOCKET_ERROR == nRecvLen ){errno = WSAGetLastError();if ( EWOULDBLOCK == errno ){#elseif ( -1 == nRecvLen ){if ( EAGAIN == errno ){errno = EWOULDBLOCK;#endif}else {cout<<endl<<"Sock::TcpRecv socket error = "<<errno;}}else if ( nRecvLen == 0 ) //套接字关闭{continue;}else{int nExtLen = (unsigned int)szbuf[4];if (nExtLen > 0){nNeeRecvLen = nExtLen;ntmpLen = nRecvLen;}}}else //接收消息扩展数据{nRecvLen = recv(tmpSock, szbuf+ntmpLen, nNeeRecvLen, 0);#ifdef WIN32if ( SOCKET_ERROR == nRecvLen ){errno = WSAGetLastError();if ( EWOULDBLOCK == errno ){#elseif ( -1 == nRecvLen ){if ( EAGAIN == errno ){errno = EWOULDBLOCK;#endif}else {cout<<endl<<"Sock::TcpRecv socket error = "<<errno;}}else if ( nRecvLen == 0 ) //套接字关闭{continue;}else{if (nNeeRecvLen == nRecvLen){szbuf[nRecvLen] = '\0';//处理数据DealData(szbuf, nRecvLen+ntmpLen);nNeeRecvLen = 0;ntmpLen = 0;}}}}}if (m_socket){closesocket(m_socket);m_socket = INVALID_SOCKET;}if (m_clientSock){closesocket(m_clientSock);m_clientSock = INVALID_SOCKET;}return 1;}int Sock::UdpRecv(){int fds,nRet;timeval tv;char szbuf[1024*4];int iTotal;fd_set fd_recv;FD_ZERO(&fd_recv);sockaddr_in addr;int iAddrSize = sizeof(addr);while (true){if (m_bExitRecv){break;}tv.tv_sec = 0;tv.tv_usec = 100000;memset(szbuf,0,sizeof(szbuf));fds = 0;FD_ZERO(&fd_recv);FD_SET(m_socket,&fd_recv);fds = m_socket;if ( fds <=0 ){#ifdef WIN32Sleep(1);#elsesleep(1);#endifcontinue;}iTotal = select(fds + 1, &fd_recv, 0, 0, &tv);#ifdef WIN32if ( SOCKET_ERROR == iTotal ){errno = WSAGetLastError();cout<<endl<<"Sock::UdpRecv socket error = "<<errno;}#elseif ( -1 == iTotal ){cout<<endl<<"Sock::UdpRecv socket error = "<<errno;}#endifif ( iTotal == 0 ) //超时{continue;}if ( FD_ISSET(m_socket,&fd_recv) )//接收{bool bCanRecv = true;while ( bCanRecv ){iAddrSize = sizeof(addr);nRet = recvfrom(m_socket,szbuf,sizeof(szbuf),0,(struct sockaddr*)&addr,#if !defined(WIN32)(socklen_t*)#endif&iAddrSize);#ifdef WIN32if ( SOCKET_ERROR == nRet ){errno = WSAGetLastError();if ( EWOULDBLOCK == errno ){#elseif ( -1 == nRet ){if ( EAGAIN == errno ){errno = EWOULDBLOCK;#endif}else //error{cout<<endl<<"Sock::UdpRecv socket error = "<<errno;}bCanRecv = false;}else{//处理数据DealData(szbuf, nRet);}}}}if (m_socket){closesocket(m_socket);m_socket = INVALID_SOCKET;}return 1;}int Sock::DealData(char *pData, int nLength){int nExtLen = 0;char szBuf[1024];memset(szBuf, 0, sizeof(szBuf));if (0xA0 == (unsigned char)pData[1])//服务端收到来自客户端的登录请求{nExtLen = (unsigned int)pData[4];memcpy(szBuf, pData+HEADER_SIZE, nExtLen);cout<<endl<<"receive data : "<<szBuf;memset(szBuf,0,sizeof(szBuf));szBuf[0] = (char)0xCC;szBuf[1] = (char)0xA1; //登录请求应答char *p = "Hello client!";nExtLen = strlen(p);memcpy(szBuf + 4, &nExtLen, sizeof(unsigned int));strcpy(szBuf + HEADER_SIZE, p);SendData(szBuf, HEADER_SIZE + nExtLen);}else if (0xA1 == (unsigned char)pData[1])//客户端收到来自服务端的登录请求应答{nExtLen = (unsigned int)pData[4];memcpy(szBuf, pData+HEADER_SIZE, nExtLen);cout<<endl<<"receive data : "<<szBuf;memset(szBuf,0,sizeof(szBuf));szBuf[0] = (char)0xCC; //发送退出请求szBuf[1] = (char)0xB0;char *p = "Hello Server, exit now";nExtLen = strlen(p);memcpy(szBuf + 4, &nExtLen, sizeof(unsigned int));strcpy(szBuf + HEADER_SIZE, p);SendData(szBuf, HEADER_SIZE + nExtLen);m_bExitRecv = true;//本端退出}else if (0xB0 == (unsigned char)pData[1]) //服务端收到来自客户端的退出请求{m_bExitRecv = true;//服务端退出}return 1;}


下边是Win32和Linux上的截图

 

 

 

 

  

原创粉丝点击