网络编程(一)
来源:互联网 发布:如何发起淘宝众筹项目 编辑:程序博客网 时间:2024/05/18 00:52
在进行网络编程之前,先把网络编程相关的重要的知识点梳理一下,但其中最最基本的网络基础知识如TCP/IP之类的知识点,还请读者自行去查阅相关的书籍
1.网络网络字节序
世界上有很多不同的种类不同的计算机,不同种类的计算在存放多字节的时候的存放顺序不同。如Intel 的 Cpu的计算机,这些地址按照“低位先存”,即这些地址字节,低位在左高字节在右。这种存放方顺序称为“little endian”顺序。而有些AMD的Unix的机器,他们的存放方式完全与intel的相反,采用网络字节序。他们按照“高位先存”,即高字节在左,低字节在右的顺序。
实际在网络编程中,大多都是用网络字节序(如TCP/IP就是采用的网络字节序 )。所以我们平时在编程时注意将 “little endian”顺序转换为网络字节序。
2.套接字的类型
套接字主要分为3类,简单说下。
1)流式套接字(SOCK_STREAM)----用于TCP
2)数据报套接字(SOCK_DGRAM) -----用于UDP
3)原始套接字(SOCK_RAW) ------原始套接字只能读取内核没有处理过的IP数据包,平时我基本没有用到.
(注意:如果你要访问其他协议的话,就必须要用原始套接字.)
3.套接字的初始化.
在套接字使用前必须,先进性初始化,在请求到适合自己或需求的版本后,我们方能进行相关方面的操作.
首先我们来看一下一个结构体,这个结构体保存的Socket相关的信息
typedef struct WSAData { WORD wVersion; //表示想获取的Socket的版本号码.低字节表示主版本号,高字节表示副版本号码 WORD wHighVersion; //windows支持的最高的sockets的版本号码 char szDescription[WSADESCRIPTION_LEN+1];//空终止,保存了socket的实现描述(基本不用) char szSystemStatus[WSASYS_STATUS_LEN+1];//空终止,保存的系统的状态或者配置信息(基本不用) unsigned short iMaxSockets; //Socket最大可以打开的数目,在WinSock2 以后的版本忽略掉 unsigned short iMaxUdpDg; //Socket数据报最大的长度,在winSock2以后的版本忽略掉 char FAR* lpVendorInfo; //为某些厂商预留的字段,在win32下不需要使用 } WSADATA, *LPWSADATA;
Winsock 初始化函数
int WSAStartup( __in WORD wVersionRequested,//我们需要的版本 __out LPWSADATA lpWSAData //返回初始化的信息);
其中版本号是一个WORD类型,我们可以通过一个宏WORD MAKEWORD(BYTEbLow, BYTE bHigh); 来生成一个字bLow低字节,bHigh高字节
在用完socket的时候,需要调用int WSACleanup(void); 终止Socket。
接着再来看一个结构体hostent ,该结构体是用来储存我们指定的主机的相关信息的。(如:主机名,IP地址等等)
typedef struct hostent { char FAR* h_name; //主机的名称 char FAR FAR** h_aliases; //地址预备名称 short h_addrtype; //地址类型 通常我们设为AF_INET(PF_INET)windows只支持这一区域的 short h_length;//每个地址的字节长度 char FAR FAR** h_addr_list;//地址列表指针,在老版本中你可能会看到h_addr,两者是一样的 } HOSTENT, *PHOSTENT, FAR *LPHOSTENT;
说明:如果你像我一样是一个新时代程序袁,一出生就是32位横行的时代,那么你可能会对FAR感到好奇。其实FAR是16位时代的产物,在32位下已经没有了类似于
near , far 之类的指针,都是一样的。就把他忽略掉就可以了。
struct hostent* gethostbyname() 通过主机名得到 主机相关的信息。
我们通过gethostbyname得到的HOSTENT,应用程序不应该试图修改或释放我们得到的任何部分,这样极有可能导致出错。
下面我们实现一个获取自己主机名和IP的小程序,代码如下:
void CGetNetInfoDlg::OnBnClickedOk(){//初始化SocketWORD wdVersion = MAKEWORD(2,2); //版本号WSADATA wsData;memset(&wsData, 0, sizeof(WSADATA)); //存放请求socket的数据if(::WSAStartup(wdVersion, &wsData)!= 0){MessageBox(_T("初始化Socket出错!"),_T("Error"),MB_OK||MB_ICONERROR);return ;}//查看版本号是否和我们的请求的一致if(LOBYTE(wsData.wVersion)!=2||HIBYTE(wsData.wVersion)!=2){MessageBox(_T("请求的版本不正确!"),_T("版本出错"),MB_OK||MB_ICONERROR);WSACleanup(); //关闭Socket}//获得主机名char hostName[MAX_PATH];memset(hostName, 0 , MAX_PATH*sizeof(char));if(::gethostname(hostName,MAX_PATH)==SOCKET_ERROR){CString str;str.Format(_T("错误号:%d"), WSAGetLastError());MessageBox(str, _T("获取主机名错误"), MB_OK||MB_ICONERROR);return;}CString strHostName(hostName);//获取主机的IPLPHOSTENT lpHost;lpHost = ::gethostbyname(hostName);CString strIpAddr;struct in_addr ip_addr;//描述IPV4的结构体if(lpHost!=NULL) //获取成功{memmove(&ip_addr, lpHost->h_addr_list[0],4);strIpAddr = CString(inet_ntoa(ip_addr));}CEdit* pEdit = NULL;pEdit = (CEdit*)GetDlgItem(IDC_ET_HOSTNAME);pEdit->SetWindowTextW(strHostName);CIPAddressCtrl* pIPCtrl;pIPCtrl = (CIPAddressCtrl*)GetDlgItem(IDC_IP_ADDR1);DWORD dwIp = ntohl(inet_addr(inet_ntoa(ip_addr)));pIPCtrl->SetAddress(dwIp);WSACleanup();//CDialogEx::OnOK();}
好了第一个超级简单的小程序,就这样搞定了。
下面我们再写一个稍微复杂点的程序,获取局域网内的所有计算机的IP。
我们 将采用枚举的方法利用下面三个函数来完成
//启动网络资源的枚举
DWORD WNetOpenEnum( __in DWORD dwScope, __in DWORD dwType, __in DWORD dwUsage, __in LPNETRESOURCE lpNetResource, __out LPHANDLE lphEnum);//2.进行枚举
DWORD WNetEnumResource( __in HANDLE hEnum, __in_out LPDWORD lpcCount, __out LPVOID lpBuffer, __in_out LPDWORD lpBufferSize);//3.结束枚举
DWORD WNetCloseEnum(__in ANDLE hEnum);code:
在void CGetNetInfoDlg::OnBnClickedOk()的末尾添加如下代码
CStringArray iparray;CStringArray namearray;FindAllComputer(iparray, namearray);CString ip = _T("");CString name = _T("");for( int i = 0; i < iparray.GetSize(); i++ ){ip = iparray.GetAt(i);name = namearray.GetAt(i);int m_nCurrentSel = m_ListCtrl.InsertItem(0xffff,_T(""));m_ListCtrl.SetItem( m_nCurrentSel, 0, LVIF_TEXT, ip, NULL, 0, 0, 0);m_ListCtrl.SetItem( m_nCurrentSel, 1, LVIF_TEXT, name, NULL, 0, 0, 0);}int error = ::GetLastError();
在OnInitDailog中初始化List控件
m_ListCtrl.InsertColumn(0, _T("局域网内计算机IP"), LVCFMT_LEFT, 200);m_ListCtrl.InsertColumn(1, _T("局域网内计算机名称"), LVCFMT_LEFT, 200);
添加如下两个函数
void CGetNetInfoDlg::FindAllComputer(CStringArray& MyList, CStringArray& MyListName){MyList.RemoveAll();CString StrTemp;struct hostent *host;struct in_addr *ptr;DWORD dwScope = RESOURCE_CONTEXT;NETRESOURCE *NetResource = NULL;HANDLE hEnum;WNetOpenEnum( dwScope, NULL, NULL, NULL, &hEnum );WSADATA wsaData;WSAStartup(MAKEWORD(1,1),&wsaData);if ( hEnum ) {DWORD Count = 0xFFFFFFFF;DWORD BufferSize = 2048;LPVOID Buffer = new char[2048];WNetEnumResource( hEnum, &Count, Buffer, &BufferSize );NetResource = (NETRESOURCE*)Buffer;char StrHostName[200];for ( unsigned int i = 0; i < BufferSize/sizeof(NETRESOURCE); i++, NetResource++ ){if ( NetResource->dwUsage == RESOURCEUSAGE_CONTAINER && NetResource->dwType == RESOURCETYPE_ANY ){if ( NetResource->lpRemoteName ){CString strFullName = NetResource->lpRemoteName;if ( 0 == strFullName.Left(2).Compare(_T("\\\\")) )strFullName = strFullName.Right(strFullName.GetLength()-2); //获得主机名gethostname( StrHostName, strlen( StrHostName ) );MyListName.Add(CString(StrHostName));char _hostName[MAX_PATH];MyWideChar_tToMultiByte(strFullName.GetBuffer(0), _hostName, sizeof(_hostName));//由主机名获得跟它对应的主机信息host = gethostbyname(_hostName);if(host == NULL) continue; ptr = (struct in_addr *) host->h_addr_list[0];// 获得机器的IP地址int a = ptr->S_un.S_un_b.s_b1; int b = ptr->S_un.S_un_b.s_b2; int c = ptr->S_un.S_un_b.s_b3; int d = ptr->S_un.S_un_b.s_b4; StrTemp.Format(_T("%s : %d.%d.%d.%d"),strFullName,a,b,c,d);MyList.Add(StrTemp);}}}delete Buffer;WNetCloseEnum( hEnum );}WSACleanup();}BOOL CGetNetInfoDlg::MyWideChar_tToMultiByte(LPTSTR lpcwszStr, LPSTR lpOut,INT nOutSize){ DWORD dwMinSize = 0; dwMinSize = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE); if(dwMinSize > nOutSize) { return FALSE; } else { WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,lpOut,nOutSize,NULL,FALSE); return TRUE; }}
最后不要忘了加上动态连接库以及头文件哈
#include <WinSock2.h>#include <Winnetwk.h>#pragma comment(lib,"Ws2_32.lib")#pragma comment(lib, "Mpr.lib")
运行效果图
因为的局域网就自己一个人,所以只出现了我自己的主机信息。
网络的基础应用就写到这吧,下一次我将写socket编程相关的内容。
- 网络编程一:网络请求
- Windows网络编程一
- Linux网络编程(一)
- C#网络编程(一)
- 网络编程技术(一)
- 网络编程 一
- 网络编程学习(一)
- 网络编程一
- 网络编程 一
- 网络编程(一)
- Java网络编程(一)
- 网络编程(一)
- 网络编程基础知识(一)
- 网络编程(一)
- 网络编程(一)
- Android网络编程一
- Windows网络编程(一)
- 网络编程(一)
- JDKDynamicProxy JDK动态代理
- 利用bat文件,自动设置IE代理
- 智能指针auto_ptr解析
- 关于BooleanQuery在搜索中的用处
- WinForm中获取鼠标当前位置
- 网络编程(一)
- 数据仓库的第一层用户的思考
- Google的5篇经典论文,分布式必读!
- Cache一致性协议 与 MESI
- PHP使用数据库永久连接方式操作MySQL的是与非
- 正则表达式和字符串处理----(转)
- (BA) SHELL 处理处理字符串的小结
- Jquery初级应用需要注意的几点
- 如何修改Code::Block的快捷键