这两天写一个远程控制的程序,在本机上测试没问题,但是换成远程测试的时候,许多问题就来了,这才发现不是简单的send和recv就可以了事的,实际的网络通信很复杂,数据不是一次发送和接受就可以成功的,所以要做判断,然后循环发送和接受。
mysocket.h
// mysocket.h: interface for the mysocket class. // // #if !defined(AFX_MYSOCKET_H__C142FE73_FC40_4235_8C9D_5E7493376017__INCLUDED_) #define AFX_MYSOCKET_H__C142FE73_FC40_4235_8C9D_5E7493376017__INCLUDED_ #include <WINSOCK2.H> #pragma comment(lib,"ws2_32"); #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #define WM_SOCKET WM_USER+1 class mysocket { public: mysocket(); virtual ~mysocket(); void init(int type=0,int protocol=1); int send(char *buf,int len,int mode=0,int flags=0); int recv(char *buf,int len,int mode=0,int flags=0); int bind(int port); int listen(int max=5); void accept(mysocket& s1); int connect(char *addr1,int port); void attach(SOCKET s1); SOCKET getsocket(); void asyncselect(HWND d,int m=FD_ACCEPT|FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE); int getport(); char *getaddr(); void close(); int sendto(char *buf,int len,char *addr,int port,int mode=0,int flags=0); int recvfrom(char *buf,int len,int mode=0,int flags=0); char* getpeer(); int getpeerport(); char* gethostbyname(char *); char* gethostbyaddr(char *); static char *getlocalip(); static void startup(); static void cleanup(); protected: sockaddr_in addr; SOCKET s; }; #endif // !defined(AFX_MYSOCKET_H__C142FE73_FC40_4235_8C9D_5E7493376017__INCLUDED_)
mysocket.cpp
#include "mysocket.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif // // Construction/Destruction // mysocket::mysocket() { } mysocket::~mysocket() { } void mysocket::startup(){ WSADATA data; WORD v=MAKEWORD(2,2); WSAStartup(v,&data); } void mysocket::cleanup(){ WSACleanup(); } void mysocket::init(int type,int protocol){ if(type==0){ s=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); }else if(type==1){ s=::socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); }else{ s=::socket(AF_INET,SOCK_RAW,protocol); } } int mysocket::send(char *buf,int len,int mode,int flags){ if(!mode){ return ::send(s,buf,len,flags); }else{ char *b=buf; sendlabel: int l=::send(s,b,len,flags); if(l==-1){ if(WSAGetLastError()!=WSAEWOULDBLOCK){ return -1; }else{ goto sendlabel; } } while(l<len){ int ll=::send(s,b+l,len-l,flags); if(ll==-1){ if(WSAGetLastError()==WSAEWOULDBLOCK){ continue; }else{ return -1; } } l+=ll; } return 1; } } int mysocket::recv(char *buf,int len,int mode,int flags){ if(!mode){ return ::recv(s,buf,len,flags); }else{ char *b=buf; recvlabel: int l=::recv(s,b,len,flags); if(l==0){ return 0; }else if(l==-1){ if(WSAGetLastError()==WSAEWOULDBLOCK){ goto recvlabel; }else{ return -1; } } while(l<len){ int ll=::recv(s,b+l,len-l,flags); if(ll==0){ return 0; }else if(ll==-1){ if(WSAGetLastError()==WSAEWOULDBLOCK){ continue; }else{ return -1; } } l+=ll; } return 1; } } int mysocket::bind(int port){ addr.sin_family=AF_INET; addr.sin_port=::htons(port); addr.sin_addr.S_un.S_addr=INADDR_ANY; return ::bind(s,(LPSOCKADDR)&addr,sizeof(addr)); } int mysocket::listen(int max){ return ::listen(s,max); } void mysocket::accept(mysocket& s1){ int n=sizeof(s1.addr); s1.s=::accept(s,(SOCKADDR*)&s1.addr,&n); } int mysocket::connect(char *addr1,int port){ addr.sin_family=AF_INET; addr.sin_port=::htons(port); addr.sin_addr.S_un.S_addr=::inet_addr(addr1); return ::connect(s,(sockaddr*)&addr,sizeof(addr)); } void mysocket::attach(SOCKET s1){ s=s1; } SOCKET mysocket::getsocket(){ return s; } void mysocket::asyncselect(HWND d,int m){ ::WSAAsyncSelect(s,d,WM_SOCKET,m); } int mysocket::getport(){ return ::ntohl(addr.sin_port); } char *mysocket::getaddr(){ return ::inet_ntoa(addr.sin_addr); } void mysocket::close(){ ::closesocket(s); } int mysocket::sendto(char *buf,int len,char *addr1,int port,int mode,int flags){ addr.sin_family=AF_INET; addr.sin_port=::htons(port); addr.sin_addr.S_un.S_addr=::inet_addr(addr1); if(!mode){ int l=::sendto(s,buf,len,flags,(sockaddr*)&addr,sizeof(addr)); return l; }else{ char *b=buf; sendtolabel: int l=::sendto(s,b,len,flags,(sockaddr*)&addr,sizeof(addr)); if(l==-1){ if(WSAGetLastError()==WSAEWOULDBLOCK){ goto sendtolabel; }else{ return -1; } } while(l<len){ int ll=::sendto(s,b+l,len-l,flags,(sockaddr*)&addr,sizeof(addr)); if(ll==-1){ if(WSAGetLastError()==WSAEWOULDBLOCK){ continue; }else{ return -1; } } l+=ll; } return 1; } } int mysocket::recvfrom(char *buf,int len,int mode,int flags){ sockaddr_in addr1; int n=sizeof(addr1); if(!mode){ int l=::recvfrom(s,buf,len,flags,(sockaddr*)&addr,&n); addr=addr1; return l; }else{ char *b=buf; recvfromlabel: int l=::recvfrom(s,b,len,flags,(sockaddr*)&addr,&n); if(l==-1){ if(WSAGetLastError()==WSAEWOULDBLOCK){ goto recvfromlabel; }else{ return -1; } } while(l<len){ int ll=::recvfrom(s,b+l,len-l,flags,(sockaddr*)&addr,&n); if(ll==-1){ if(WSAGetLastError()==WSAEWOULDBLOCK){ continue; }else{ return -1; } } l+=ll; } return 1; } } char* mysocket::getpeer(){ sockaddr_in addr; int n=sizeof(addr); ::getpeername(getsocket(),(sockaddr*)&addr,&n); // int peerport=::ntohs(addr.sin_port); return ::inet_ntoa(addr.sin_addr); } int mysocket::getpeerport(){ sockaddr_in addr; int n=sizeof(addr); ::getpeername(getsocket(),(sockaddr*)&addr,&n); return ::ntohs(addr.sin_port); } char* mysocket::gethostbyname(char *url){ HOSTENT *pHostEnt; struct sockaddr_in sAddr; pHostEnt = ::gethostbyname( url); memcpy ( &sAddr.sin_addr.s_addr, pHostEnt->h_addr_list[0], pHostEnt->h_length); return inet_ntoa(sAddr.sin_addr); } char* mysocket::getlocalip(){ HOSTENT *pHostEnt; struct sockaddr_in sAddr; char hostname[256]; int res = gethostname(hostname, sizeof(hostname)); pHostEnt = ::gethostbyname( hostname); memcpy ( &sAddr.sin_addr.s_addr, pHostEnt->h_addr_list[0], pHostEnt->h_length); return inet_ntoa(sAddr.sin_addr); } char* mysocket::gethostbyaddr(char *ip){ // ULONG a; // a = inet_addr(ip); // try{ //return ::gethostbyaddr((char *)&a, sizeof(a),AF_INET)->h_name; // }catch(...){ return "null"; // } }
对send,sendto,recv,recvfrom加了mode参数,默认值为0 ,既一般发送,为1时为完全发送模式,即将需要发送和接受的数据按指定大小完全接受和发送后才返回。另外还加了个startup和cleanup两个静态函数,用于初始化winsock库和释放用的。原本想加个gethostbyaddr方法,但是测试的时候老是错误,具体原因不知,所以就直接返回null了。
本文有不足之处,还望大家多多指正。