作为一名初学者,和大家一样,对网络这个东西敬之迷之却又惑之。对我而言,最爽的就是弄懂那些自己不知道的东西了。那么,咱么就一起学习socket编程吧!
一、主机地址、ip地址、网络号、主机号、域名 WTF?
首先,设备想要在互联网的大海里遨游就必须的有一个自己在这个圈子里唯一的标识,这就是ip地址,一般来说,ip地址具有唯一性,就像在学校里你的学号是独一无二的一样。ip地址包括网络号和主机号两个部分,比如百度的ip:123.125.115.110,前三段(123.125.115)即是它的网络号,最后一段(110)就是它的主机号。由于ip地址这一堆堆的数字老是让人记不住,所以机智的人类发明了域名。域名和ip可以是一一对应,也可以是一个域名对应多个ip(比如百度就有两个ip,但是只有一个baidu.com域名)。ip地址就是主机地址。
二、ip地址在计算机里是如何存储的?
说白了,ip就是一串数字,目前为止是32bit的无符号数。
三、网络是怎样连通的?
在数据传输的过程中,必定存在两端,一端发送数据,一端接收数据,因此出现了客户端和服务器,但不是说客户端就一定只能接收数据,服务器就只能发送数据,在通信时,往往两端都有在发送和接受数据。这里要特别注意一点:客户端和服务器并不单纯的只是两台设备,他们是两个进程。换句话说,一台设备上可能跑多个客户端或者多个服务器。网络就是依靠两端的某些信息而建立的,包含这些信息的结构叫做套接字对,而这些信息本身就是套接字。套接字包含了主机地址和端口号。处于客户端的套接字成为客户端套接字,处于服务器端的套接字称为服务器套接字。当两台设备想要连接起来以便通信时,我们可以调用 套接字接口 来让他们完成“交易”结合成对,当“交易”完成时,他们就可以愉快的相互“说话”了。
四、套接字接口
套接字接口分为客户端套接字接口和服务器端套接字接口。
客户端套接字接口:getaddrinfo()、socket()、connect()、rio_writen()、rio_readlineb()、close()
服务器端套接字接口:getaddrinfo()、socket()、bind()、listen()、accept()、rio_readlineb()、rio_writen()、close()
当然,套接字接口还不止这些,这些只是完成客户端与服务器相互连通并进行简单的数据传输所用到的套接字接口。
五、小试身手
了解到这,我们可以来做一个小实验,来看看百度域名到底映射了多少ip。
第一步:我们得进行socket版本协商,初始化socket;
第二步:填充addrinfo结构体(结构体的具体细节百度吧,这里就不贴了)
第三步:根据域名获取映射ip存于addrinfo链表中
第四步:获取域名的数字地址字符串
第五步:为了养成良好的编程习惯,切不要忘了结束时应该释放内存
搞定!哦,对了,差点忘了贴代码了...
1 #include <iostream> 2 #include <ws2tcpip.h> 3 #pragma comment(lib,"ws2_32.lib") 4 5 int main(int argc, char* argv[]) 6 { 7 const int MAXLINE = 2048; 8 struct addrinfo *p, *listp, hints; 9 char buf[MAXLINE]; 10 int rc, flags; 11 12 //第一步:进行socket版本协商并初始化socket(使用socket函数之前的必要步骤) 13 WORD wVersionRequested; 14 WSADATA wsaData; 15 int err; 16 17 wVersionRequested = MAKEWORD(1, 1); 18 19 err = WSAStartup(wVersionRequested, &wsaData); 20 if (err != 0) { 21 /* Tell the user that we could not find a usable */ 22 /* WinSock DLL. */ 23 return 0; 24 } 25 26 /* Confirm that the WinSock DLL supports 1.1.*/ 27 /* Note that if the DLL supports versions greater */ 28 /* than 1.1 in addition to 1.1, it will still return */ 29 /* 1.1 in wVersion since that is the version we */ 30 /* requested. */ 31 32 if (LOBYTE(wsaData.wVersion) != 1 || 33 HIBYTE(wsaData.wVersion) != 1) { 34 /* Tell the user that we could not find a usable */ 35 /* WinSock DLL. */ 36 int vl = LOBYTE(wsaData.wVersion); 37 int vh = HIBYTE(wsaData.wVersion); 38 return 0; 39 } 40 41 /* The WinSock DLL is acceptable. Proceed. */ 42 43 /*if (argc != 2) 44 { 45 fprintf(stderr, "usage:%s <domain name> ", argv[0]); 46 exit(0); 47 }*/ 48 49 //end 50 51 char name[50]; 52 std::cin >> name; 53 54 //第二步:填充addrinfo结构体 55 memset(&hints, 0, sizeof(struct addrinfo)); 56 hints.ai_family = AF_INET; 57 hints.ai_socktype = SOCK_STREAM; 58 //end 59 60 //第三步:根据域名name获取映射ip存于listp中 61 if ((rc = getaddrinfo(name, NULL, &hints, &listp)) != 0) 62 { 63 std::cout << "getaddrinfo error:" << gai_strerror(rc) << std::endl; 64 WSACleanup(); 65 return 0; 66 } 67 //end 68 69 //第四步:获取域名的数字地址字符串 70 flags = NI_NUMERICHOST; 71 for (p = listp; p; p = p->ai_next) 72 { 73 getnameinfo(p->ai_addr, p->ai_addrlen, buf, MAXLINE, NULL, 0, flags); 74 std::cout << buf << std::endl; 75 } 76 //end 77 78 //第五步:释放listp(由于较小所以可以忽略,只是为了养成良好的编程习惯最好加上) 79 freeaddrinfo(listp); 80 //end 81 system("pause"); 82 WSACleanup(); 83 return 0; 84 }
说明:本代码基于vs2015调试运行成功。由于DEV C++中不认识#pragma,因此在DEV C++中不能运行。还请注意,windows下,套接字接口包含于头文件<ws2tcpip.h>中,同时还应将其配套的库“ws2_32.lib”一起包含在程序里,不然会出现这个情况:
//error LNK2019: 无法解析的外部符号 __imp__WSAStartup@8,该符号在函数 _main 中被引用
在linux下,头文件为<netdb.h>。
入门篇结束~待续...