当前位置: 首页 > news >正文

网站解析不过来怎样给公司做网站

网站解析不过来,怎样给公司做网站,房产做网站是什么意思,全面的上海代理注册公司#x1f431;作者#xff1a;一只大喵咪1201 #x1f431;专栏#xff1a;《网络》 #x1f525;格言#xff1a;你只管努力#xff0c;剩下的交给时间#xff01; 在前面本喵对网络的整体轮廓做了一个大概的介绍#xff0c;比如分层#xff0c;协议等等内容#x… 作者一只大喵咪1201 专栏《网络》 格言你只管努力剩下的交给时间 在前面本喵对网络的整体轮廓做了一个大概的介绍比如分层协议等等内容现在我们直接进入socket(套接字)编程先来感受到网络编程。 UDP套接字 预备知识源IP地址和目的IP地址端口号port网络通信的本质 认识TCP/UDP协议网络字节序主机和网络的字节序转换函数 socket套接字socket常见系统调用sockaddr结构体 UDP网络编程服务端实现客户端实现 用户层与网络的解耦总结 预备知识 源IP地址和目的IP地址 我们知道在网络通信中存在两套地址一套是IP地址另一套是MAC地址。 IP地址标识计算机在网络中的唯一性。 而IP地址又分为源IP地址和目的IP地址 源IP地址标识网络通信发起方。 目的IP地址标识网络通信的接收方。 在网络通信的报文中其中报头包含着源IP和目的IP。 端口号port 如上图所示报文从用户A的计算机传送到了用户B的计算机但是网络通信的目的就是将报文从一台计算机传送到另一台计算机吗 将数据从计算机A传送到计算机B是手段并不是网络通信的目的。真正进行通信的是用户A和用户B也就是计算机A上的某个应用程序和计算机B上的某个应用程序之间在通信。 网络通信的目的就是让两台计算机上的两个进程在进行通信。 IP地址可以标识两台计算机的唯一性但是每台计算机上会存在大量的进程如何保证计算机A某个进程发送的数据能让计算机B指定的进程接收到呢 换句话说如何标识一台计算机上进程的唯一性呢 采用端口号port来标识计算机上进程的唯一性。 端口号是一个2字节16位的整数。端口号用来标识一个进程告诉操作系统要把数据交给哪一个进程。一个端口号只能被一个进程占用。 现在我们有用来标识计算机在网络中唯一性的IP地址又有用来标识进程在计算机中唯一性的端口号port。 全网唯一进程 IP地址(全网主机唯一性) 端口号port(该主机上进程唯一性) socket(套接字) IP地址 端口号port。 所以要想两个进程间实现通信必须各自有各自的套接字。 网络通信的本质 网络通信实际上是两台计算机或者多台计算机上的进程之间在通信和我们之前Linux学习的进程间通信的区别在于进程位于不同的计算机上。 网络通信的本质进程间通信。 要实现进程间通信必须有共享资源而网络通信中的网络就是共享资源。 网络通信其实就是在做IO我们上网的所有行为就两种a. 把数据发出去。 b. 把数据读回来。 Linux下一切皆文件所以网络在系统中也是一个文件也有struct结构体也有文件描述符。 我们知道每个进程都有一个pid来标识它在当前计算机上的唯一性为什么网络中还需要一个端口号port来标识进程的唯一性呢不能用pid吗 在技术实现上是完全可以用pid的所以就需要考虑为什么偏偏就用了端口号port 系统是系统网络是网络系统使用pid网络使用port来标识进程的唯一性实现了系统与网络的解耦。不是所有进程都提供网络服务或者网络请求的但是所有的进程都需要pid只有需要网络的进程才会分配一个port。客户端需要能够直接找到服务器的进程服务器进程的唯一性不能做任何改变。 比如我们平时使用的QQ我们手机上的QQ都是客户端我们打开QQ使用都是在向服务器上的QQ进程发起网络请求而这个服务器位腾讯公司服务进程根据用户的网络请求再做出对应的反馈交给用户。 我们下载了某个应用程序以后该程序里就绑定了服务端对应进程的IP地址和端口号。所以使用应用程序的时候就能精准的和服务端上对应的进程进行网络通信。 服务器的IP地址并不会随意变化为了保证客户端每次都能找到服务端的进程服务端的port也不能变化。 如果使用pid来代替端口号的话服务器每重启一次服务进程的pid值就会改变客户端就无法找到服务进程了。 绑定了port的进程PCB会被维护在一个哈希表中port就是key值操作系统能够根据key值找到对应的PCB然后再执行它。 认识TCP/UDP协议 这两个协议的具体原理和细节在后面本喵会详细讲解这里仅需要大概了解一下它两的特定即可。 TCP协议:(Transmission Control Protocol 传输控制协议)。 传输层协议。需要通信双方建立连接。是一种可靠传输不会发生丢包等问题。面向字节流。 UDP协议:(User Datagram Protocol 用户数据报协议)。 传输层协议。不需要通信双方建立连接直接发生即可。不可靠传输可能会发生丢包等问题。描写数据报。 具体这些特点是什么意思以后会讲解到这里只需要记住以上内容即可。 网络字节序 我们的计算机分为大端机和小端机不同的电脑型号就不一样两台计算机大小端不同接收到的数据解释出来意义也不同。 规定网络中的字节序都采用大端。 如果你的计算机是大端机那么就可以直接向网络中发数据和从网络中接收数据不用做转换。 如果你的计算机是小端机那么在向网络中发送数据时需要先将数据转换成大端再发送到网络中。从网络中接收下来的数据需要先转换成小端再使用。 此时就存在两个问题 自己的电脑是大端还是小端还需要自己去判断一下。如果自己的电脑是小端需要自己去将数据转换成大端。 这两个问题虽然我们自己能解决但是比较繁琐而且很容易出错所以操作系统提供了相应的接口来进行大小端转换 主机和网络的字节序转换函数 #include arpa/inet.h//必须包含的头文件 // 主机序列转网络序列 uint32_t htonl(uint32_t hostlong);//将主机上unsigned int类型的数据转换成对应网络字节序 uint16_t htons(uint16_t hostshort);//将主机上unsigned short类型的数据转换成对应网络字节序 // 网络序列转主机序列 uint32_t ntohl(uint32_t netlong);//将从网络中读取的unsigned int类型的数据转换成当前计算机字节序 uint16_t ntohs(uint16_t netshort);//将从网络中读取的unsigned short类型的数据转换成当前计算机字节序这些函数名很好记h表示host代表着主机n表示network代表着网络s表示unit16_tl表示uint32_t。如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回。如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。 socket套接字 socket常见系统调用 socket socket系统调用专门用来创建套接字在创建的时候指定使用哪种通信协议。 参数解释 int domain 这是地址族用来指定创建的套接字进行的是网络通信还是本地通信。 该参数可以填上图所示中的任何一个经常使用的是AF_INET表示使用IPv4的网络套接字进行网络通信 int type 这是用来指定socket提供的能力类型比如是面向字节流还是面向用户数据报。 该参数可以使用上图中的任何一个其中画红色框的是面向字节流和面向用户数据报也就是TCP和UDP。 int protocol 该参数是用来指定具体的协议名的比如指定TCP或者DUP但是根据前两个参数就可以确定使用哪个协议了这个一般设置为0即可。 返回值 int 成功返回一个int类型的值其实就是一个文件描述符sockfd。失败返回-1并且设置错误码errno。 bind bind用来将IP地址和端口号port创建的socket套接字绑定也就是将IP地址和端口号port和系统绑定。 参数解释 int sockfd 使用socket()返回的文件描述符sockfd用来指定绑定哪个套接字。 const struct sockaddr * addr struct sockaddr是一个结构体。 socklen_t addrlen 这个参数是表示sockaddr结构体大小的单位是字节socklen_t本质是unsigned int类型的32位变量。 返回值int 成功返回0失败返回-1并且设置错误码errno。 其他几个接口 // 开始监听socket (TCP, 服务器) int listen(int socket, int backlog); // 接收请求 (TCP, 服务器) int accept(int socket, struct sockaddr* address, socklen_t* address_len); // 建立连接 (TCP, 客户端) int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);这几个接口的是TCP协议才会用到后面本喵再详细讲解。 sockaddr结构体 套接字有很多种类型常见的有三种 网络套接字用户跨主机之间的通信也能支持本地通信。原始套接字可以跨过传输层(TCP/UDP)访问底层的数据。域间套接字只能在本地通信。 这些套接字的应用场景完全不同所以不同种类的套接字就对应一套系统调用接口所以三套就会对应三套不同的接口。 网络套接字 struct sockaddr_in {short int sin_family; // 地址族一般为AF_INETunsigned short int sin_port; // 端口号网络字节序struct in_addr sin_addr; // IP地址unsigned char sin_zero[8]; // 用于填充使sizeof(sockaddr_in)等于16 };通过sockaddr_in结构体将IP地址端口号以及网络通信AF_INET通过系统调用bind与系统绑定从而进行网络通信。 域间套接字 struct sockaddr_un {sa_family_t sun_family; /* AF_UNIX */char sun_path[108]; /* 带有路径的文件名 */ };sockaddr_un只有域间通信方式AF_UNIX以及域间通信的路径名。 而设计者为了方便使用无论是网络通信还是域间通信都使用一套接口通过设置不同参数来解决所有通信场景。 sockaddr_in和sockaddr_un是用于网络通信和域间通信两个不同的通信场景它们的区别就在于结构体起始处的16位地址类型不同网络通信使用AF_INET域间通信使用AF_UNIX。 但由于要使用一套接口所以此时无论哪种通信都使用sockaddr结构体。 在填充IP地址端口号以及地址类型的时候仍然是对sockaddr_in进行填充。在使用bind系统调用时将sockaddr_in强转成sockaddr类型在函数内部它会根据前两个字节自行判断是什么类型的通信然后再强制转回去。 可以将sockaddr看成是基类把sockaddr_in和sockaddr_un看出是派生类此时就构成了多态体系。 UDP网络编程 网络通信一定是双方的一端是服务端(Server)接收数据另一端是客户端(Client)发送数据。 服务端实现 网络通信首先就是要有套接字也就是要有IP地址和端口号port所以我创建的服务器中必须有这两项。 class udpSever { private:uint16_t _port;//服务进程端口号string _ip;//服务器ip地址int _sockfd;//socket返回值 };使用系统调用socket()时相当于打开了服务器的网卡在系统中会创建一个struct file类型的结构体来描述网卡的信息和文件操作类型所以会返回一个sockfd这其实就是一个文件描述符。所以服务器的成员变量有上面代码所示的三个。 在构造函数构造服务器对象的时候需要传入端口号port和IP地址。 端口号port是指定的一旦指定就不能再更改这里本喵指定为8080。IP地址是服务器的IP地址。 在shell上使用指令ifconfig可以看到服务器的IP信息如上图所示红色框中的inet:127.0.0.1是本地环回使用这个IP地址不会经过物理层将数据发出去而且从链路层又返回到了当前计算机。 如上图所示数据从当前计算机上的客户端进程流向了当前计算机上的服务的进程。所以可以使用本地环回IP地址来进行测试。 但是我们知道每台计算机在网络中都有一个公网IP这个IP和本地回环不一样还有局域网IP等等。存在这么多IP都标识着服务器这一台计算机。 如果服务器仅仅绑定本地换行的IP地址当另一台计算机的服务端想要通过公网IP地址发起申请的时候由于两个IP地址不一样所以就会忽略客户端的申请。 为了能够让服务端接收所有的网络请求将服务器的IP地址绑定为0.0.0.0转换成uint32_t类型就是0。 其实每台计算机绑定的都不止一个IP当使用bind绑定的IP地址是0.0.0.0的时候这台计算机收到的所有网络请求都会接收并且根据相应的端口进行处理。 所以本喵将udpSever中构造函数IP地址形参设为缺省值 static const string defaultIP 0.0.0.0; //构造函数 udpSever(const uint16_t port, const string ip defaultIP): _port(port), _ip(ip), _sockfd(-1) {}initSever() 在这个初始化函数中创建socket并且和操作系统进行绑定bind。 使用socket()系统调用创建套接字并且进行判断创建失败打印相应错误信息并且退出进程。填充sockaddr_in结构体 首先需要对该结构体进行初始化也就是清0和填充使用函数bzero进行初始化 这是一个库函数需要包含头文件strings.h该函数的作用和memset一样不同之处在于bzero只能清零第一个参数是目标地址第二个参数是要清零的字节数。 在填充sockaddr_in结构体的时候将地址类型sin_family填充为AF_INET表示网络通信。 在填充端口号sin_port的时候需要使用htons()函数将主机字节序转换成网络字节序然后再进行填充。 我们平时看到的IP地址是都是点分十进制的如127.0.0.1这是一个字符串这是为了方便用户阅读其实在网络中IP地址是一个uint32_t类型的数据。 所以在填充IP地址地址的时候需要先将点分十进制的IP地址使用函数inet_addr()转换成网络类型的uint32_t类型然后再进行填充。 形参是const char* cp也就是点分十进制的IP地址返回类型是in_addr_t。 typedef uint32_t in_addr_t其实就是uint32_t类型只是重命名成了in_addr_t。 再使用bind将IP地址和端口号和系统绑定在绑定之前sockaddr_in是在栈区上的操作系统根本不知道设的值是什么只有使用bind之后才真正将IP地址和端口号绑定到了操作系统中。 在绑定完成后进行判断如果失败打印相应错误信息并且退出进程。 这里使用枚举来列举错误码在创建套接字和绑定的时候如果发生了错误在进程退出时给与相关的错误码。 至此UDP服务器网络通信的预备工作全部完成此时就可以进行网络通信了。 start() 在预备工作做好以后还需启动服务器服务器进程是一个常驻内存的进程也就是一个while(1)的死循环在这个循环中进行网络数据的接收处理以及发送。 上图所示的系统调用recvfrom()用来接收网络中发过来的数据也就是从套接字中接收。 第一个参数是sockfd是创建套接字时返回的文件描述符fd。第二个参数buf是用来存储从网络中读取下来的数据的。第三个参数是buf缓冲区的大小。第四个参数flags是读取的方式一般设置为0即阻塞读取数据。第五个参数sockaddr* src_addr是一个输出型参数同样传参sockaddr_in结构体系统会自动对这个结构体进行填充可以获取数据的来源包括发送方的地址类型端口号port以及IP地址。第六个参数addrlen是第五个输出型结构体变量的大小所在的地址注意类型是socklen_t*的和bind的时候不一样。返回值ssize_t返回读取到的数据个数单位是字节如果读取失败则返回-1。 如上图所示代码服务端启动后便常驻内存网络中有数据便读没有数据便阻塞等待。 读取数据时除了数据本身还有发送方的数据都在sockaddr_in类型的结构体peer中。 从网络中获取到发送方的IP地址是uint32_t类型的所以需要使用inet_ntoa()函数将其转换成点分十进制的方便用户阅读。 红色框中所示就是inet_ntoa的函数声明以字符串的形式返回点分十进制的IP地址参数类型是struct in_addr in。 in_addr结构体中的变量其实就是一个uint32_t类型的但是这里传参的时候不需要具体到s_addr直接传结构体就行和绑定IP地址时填充sockaddr_in不一样。 此时我们就可以创建服务器对象并且开始使用他了。 udpSever.cpp 在运行可执行程序的时候需要输入命令行参数由于IP地址设置了缺省值所以命令行参数只需要一个端口号即可。 如果执行时命令行参数没有输对进程就会退出并且打印使用信息如果命令行参数输入正确就向下执行。 使用一个智能指针unique_ptr来管理服务器对象然后再初始化initSever之后再开始执行服务器进程start。 此时服务器进程就开始运行了。那么我们怎么知道它是否运行了呢 使用指令sudo netstat -nuap可以查看当前服务器上的网络进程如上图所示。 加sudo提权如果不加打印的信息不完整。 可以看到存在一个网络进程IP地址是0.0.0.0端口号是8080进程pid是376进程名字是udpSever和我们设定的一样。 至此服务端的工作就做完了只有客户端发送数据服务端就可以收到。 客户端实现 class udpClient { public://构造函数初始化服务端IP地址和端口号udpClient(const string severip, const uint16_t port):_severip(severip),_severport(severport),_sockfd(-1){} private:int _socketfd;//套接字文件描述符string _severip;//服务器IP地址uint16_t _severport;//服务器端口号 };对于客户端只需要知道服务端计算机的IP地址和端口号port即可不需要知道自己的在使用构造函数构建客户端对象的时候需要传入服务端的IP地址和端口号。 客户端有无数个但是服务端只有一个。 initClient 客户端的初始化中只需要创建套接字即可不需要显式bind。 对于客户端而言指定唯一的IP地址和端口号没有意义除了服务器以外没有其他用户会向客户端发起网络请求。 run() 在发送数据之前需要先告诉操作系统要把数据发送到哪里所以需要指定服务器的IP地址和端口号port所以同样需要填充sockaddr_in结构体创建一个sever变量。 指定地址类型为网络通信将点分十进制的IP地址转换成uint32_t类型再将端口号转换成网络字节序。 向网络中发送数据的时候使用到的系统调用是sendto() 第一个参数sockfd是创建的套接字的文件描述符。第二个参数buf是要发送的数据所在的缓冲区。第三个参数len是要发生的数据个数以字节为单位。第四个参数flags是发送方式一般设置为0表示阻塞发送。第五个参数dest_addr是存放服务器IP地址和端口号port的sockaddr_in结构体变量在传参的时候需要强转为struct sockaddr*。第六个参数是第五个参数中结构体变量的大小以字节为单位。 在调用sendto向网络中发送数据的时候操作系统会自动将客户端的IP地址和端口号绑定并且一起发送出去。 由于客户端不需要指定端口号IP地址也是固定的所以操作系统会随机给客户端分配一个端口号使用。 在服务端收到客户端的报文中就包含着客户端的IP地址和端口号通过从recvfrom填充的sockaddr_in结构体中可以提取客户端操作系统随机分配的那个端口号。 服务端同样可以根据这个IP地址和端口号再给客户端发送消息。 udpClient.cpp 在运行udpClient的时候需要传入两个命令行参数一个是服务器的IP地址一个是服务器的端口号port。 同样使用unique_ptr智能指针来管理客户端对象创建好后进行初始化然后开始运行。 由于本喵是在一台服务器上测试客户端和服务端所以使用的是本地环回本地环回的IP地址就是127.0.0.1所以第一个命令行参数就是这个第二个命令行参数是服务器指定的端口号前面本喵指定的是8080。 IP地址使用公网IP局域网IP还有本地环回IP服务端都可以收到客户端的请求因为服务端绑定的是0.0.0.0。 可以看到在客户端运行起来以后打印信息socket success: 3打印的这个数字就是套接字的文件描述符之所以是3是因为012被标准输入输出以及标准错误占用了。 更进一步说明了套接字创建好后在操作系统中就是一个文件也是一个结构体。 此时客户端和服务端都执行起来了双方就可以进行通信了 运行客户端进程并且输入要发送的数据内容如上图所示。 可以看到客户端发送的内容服务端收到了并且还有客户端的IP地址和端口号。 重新运行客户端程序发送数据可以看到客户端新收到的数据中端口号变了从45839变成了47530这是因为客户端的端口号是由操作系统分配的并不是自己指定的所以每次运行时端口号都不一样。 用户层与网络的解耦 上面我们成功的让客户端和服务端建立起了连接并且能正常进行网络通信现在我们让服务端用户层和网络进行解耦。 在服务端中增加回调函数_callback使用function包装回调函数的类型是void(int, string, uint16_t, string)。 现在我们实现一个英汉互译的词典客户端输入英文单词服务端查它对应的汉语并且返回给客户端。 先在当前路径下创建一个dict.txt文件里面放入英文和对应的汉语。在main函数中加载词典调用initDict()函数。在初始化函数中使用ifstream类打开dict.txt词典文本再调用cutString()将文本中的英文和中文分开。将分开的英文和中文以键值对的形式插入全局变量unordered_map中。 此时我们的词典就建成了本喵只是简单的写了几个英文单词。 服务器用户层的回调函数 在回调函数中使用从网络中接收到的客户端请求也就是英文单词在unordered_map中查找对应的中文意思如果找到了将中文赋值给response_message如果没有找到则将unkonwn赋值给response_message。 然后将查询的结构response_message通过网络发送给客户端。 可以看到此时就实现了用户层和网络的解耦用户要进行的操作完全由用户自己在回调函数中实现即可。网络底层的配置不用做任何改变。 由于客户端还要接收服务端的反馈信息所以客户端的网络底层需要做一些修改 在客户端发送完数据以后便开始等待服务端的反馈如果服务端发送来信息则接收并且打印在屏幕上。 这个例子中打印的就是客户端发送英文单词对应的中文意思。 客户端程序运行起来后输入英文单词如上图所示红色框就会得到对应的中文如上图绿色框所示。 翻译的过程是由服务器完成的客户端只需要将英文单词交给服务器即可。 服务端可以看到客户端发来的英文单词如上图绿色框中所示。具体的翻译逻辑是在回调函数中实现的。 如此一来我们英汉互译词典的功能就实现了。 还可以做一些相关的改进此时的客户端发送数据和读取数据都是阻塞的在发送完毕后只能等数据到来再去读取程序不会执行下去。可以将发送和读取弄成两个线程去执行此时发送和读取就不不干涉了。 总结 UDP协议的网络通信非常简单只需要使用socket()创建套接字服务器的话需要显式bind客户端不需要显式bind还有就是需要使用recvfrom从网络中(套接字)中读取数据以及使用sendto向网络中(套接字)中发送数据。
http://wiki.neutronadmin.com/news/224658/

相关文章:

  • 网站内容设计vultr 宝塔安装wordpress
  • 禄丰县住房和城乡建设局网站站长之家网站流量查询
  • 东莞网站建设如何做做服装外贸的网站
  • 如何做网站霸屏wordpress怎么安装模板
  • 用手机怎么做免费网站wordpress 获取链接地址
  • 张店网站设计新网站建设代理商
  • 大良网站智能推广机构网页设计心得500字
  • 深圳网站制作平台学做家常菜去那个网站
  • 网站系统开发团队简介宜春公司网站建设
  • 找网站建设的企业公司网站建设实施方案
  • 甘肃网络公司网站建设甘肃定西校园文化设计公司
  • 医院网站建设的规划 百度一下
  • 做推文的编辑网站网站建设相关优化
  • 网站建设公司 预算可以做描文本的网站
  • 郑州网站建设 seodz增加网站标签
  • 现在做什么网站好产品平面广告设计
  • 五金网站方案企业宣传网站建设内容
  • 唐山网站设计公司天津营销型网站建设公司
  • seo排行榜年度10佳网站苍溪规划和建设局网站
  • 用什么程序做网站最好优化个人网站源代码下载
  • 免费做网站哪里有免费ftp服务器空间
  • 网站营销方法学习网首页
  • 网站建设高校怎样做淘客网站
  • 做网站工作条件做新闻微网站有哪些方面
  • 北京市两学一做网站wordpress更改链接后网站打不开
  • 平台制作专业网站制作如何做网站轮播图和菜单全屏
  • 汽配网站开发wordpress导入数据库
  • 珠海网站建设维护网站设计评价
  • 电子商务网站建设实训实践总结wordpress迁服务器
  • 专业做医院网站vs2010网站开发登录代码