本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()) { //创建并绑定本端Socket nRet = 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 WIN32 system("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 5679 class 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 short m_localPort; unsigned long m_remoteIp; unsigned short m_remotePort; int m_nProtocol; SOCKET m_socket; SOCKET m_clientSock; int m_recvBuffSize; int m_sendBuffSize; int m_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 WIN32 WSADATA wsa = {0}; int ret = WSAStartup(MAKEWORD(2,2), &wsa); if (ret != 0) { return -1; } #endif return 1; } int Sock::CleanUp() { #ifdef WIN32 if (WSACleanup() == SOCKET_ERROR) { return -1; } #endif return 1; } int Sock::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 WIN32 errno = WSAGetLastError(); #endif if (m_socket == INVALID_SOCKET) { return -1; } int nBlock = 1; //设为非阻塞模式 int nRet; #ifdef WIN32 nRet = ::ioctlsocket(m_socket,FIONBIO,(u_long FAR *)&nBlock); if (nRet == SOCKET_ERROR) { errno = ::WSAGetLastError(); nRet = -1; } #else nBlock = ::fcntl(m_socket, F_GETFL, 0); if (nBlock != -1) { nBlock |= O_NONBLOCK; nRet = ::fcntl(m_socket, F_SETFL, nBlock); } #endif if ( -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 WIN32 if ( SOCKET_ERROR == nRet && (errno = WSAGetLastError()) == EWOULDBLOCK) { #else if ( -1 == nRet && EINPROGRESS == errno ) { errno = EWOULDBLOCK; #endif fd_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 WIN32 if ( SOCKET_ERROR == nRet ) { errno = WSAGetLastError(); closesocket(m_socket); m_socket = INVALID_SOCKET; return -1; } #else if ( -1 == nRet ) { closesocket(m_socket); m_socket = INVALID_SOCKET; return -1; } #endif if ( 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; } } #endif if ( fds <=0 ) { #ifdef WIN32 Sleep(1); #else sleep(1); #endif continue; } iTotal = select(fds + 1, &fd_recv, 0, 0, &tv); #ifdef WIN32 if ( SOCKET_ERROR == iTotal ) { errno = WSAGetLastError(); cout<<endl<<"Sock::TcpRecv socket error = "<<errno; } #else if ( -1 == iTotal ) { cout<<endl<<"Sock::TcpRecv socket error = "<<errno; } #endif if ( 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 WIN32 errno = WSAGetLastError(); #endif cout<<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 WIN32 nRet = ::ioctlsocket(m_clientSock,FIONBIO,(u_long FAR *)&nBlock); if (nRet == SOCKET_ERROR) { errno = ::WSAGetLastError(); nRet = -1; } #else nBlock = ::fcntl(m_clientSock, F_GETFL, 0); if (nBlock != -1) { nBlock |= O_NONBLOCK; nRet = ::fcntl(m_clientSock, F_SETFL, nBlock); } #endif if ( -1 == nRet ) { cout<<endl<<"Sock::TcpRecv socket error = "<<errno; } } continue; } else { tmpSock = m_clientSock; } #else tmpSock = m_socket; #endif if ( 0 == nNeeRecvLen ) //接收消息32位头 { nNeeRecvLen = HEADER_SIZE; nRecvLen = recv(tmpSock, szbuf, nNeeRecvLen, 0); #ifdef WIN32 if ( SOCKET_ERROR == nRecvLen ) { errno = WSAGetLastError(); if ( EWOULDBLOCK == errno ) { #else if ( -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 WIN32 if ( SOCKET_ERROR == nRecvLen ) { errno = WSAGetLastError(); if ( EWOULDBLOCK == errno ) { #else if ( -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 WIN32 Sleep(1); #else sleep(1); #endif continue; } iTotal = select(fds + 1, &fd_recv, 0, 0, &tv); #ifdef WIN32 if ( SOCKET_ERROR == iTotal ) { errno = WSAGetLastError(); cout<<endl<<"Sock::UdpRecv socket error = "<<errno; } #else if ( -1 == iTotal ) { cout<<endl<<"Sock::UdpRecv socket error = "<<errno; } #endif if ( 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 WIN32 if ( SOCKET_ERROR == nRet ) { errno = WSAGetLastError(); if ( EWOULDBLOCK == errno ) { #else if ( -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上的截图