网站开发外包方案,教做月嫂的网站有吗,有赞商城官网,天津设计公司联系方式预备知识
源IP地址和目的IP地址
在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址
认识端口号
端口号(port)是传输层协议的内容. 端口号是一个2字节16位的整数;端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪个进程来处理;IP地址 端口号能…预备知识
源IP地址和目的IP地址
在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址
认识端口号
端口号(port)是传输层协议的内容. 端口号是一个2字节16位的整数;端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪个进程来处理;IP地址 端口号能够标识网络上的某一台主机的某一个进程;一个端口号只能被一个进程占用 传输层协议(TCP和UDP)的数据段中有两个端口号, 分别叫做源端口号和目的端口号. 就是在描述 数据是谁发的, 要发给谁
简单认识TCP协议 传输层协议有连接可靠传输面向字节流 简单认识UDP协议 传输层协议无连接不可靠传输面向数据报 网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?
补充 计算机在存储数据时是有大小端的概念的 大端模式 数据的高字节内容保存在内存的低地址处数据的低字节内容保存在内存的高地址处。 小端模式 数据的高字节内容保存在内存的高地址处数据的低字节内容保存在内存的低地址处。 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可; 网络字节序与主机字节序之间的转换 为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
#include arpa/inet.huint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort); 这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。ntoh表示网络转主机hton表示主机转网络例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。 socket编程接口
socket常见API
创建 socket 文件描述符 (TCP/UDP, 客户端 服务器)
int socket(int domain, int type, int protocol);绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);开始监听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);在上面的的这些接口中可以发现这里面有一个结构体指针sockaddr* 那么这个sockaddr结构体到底是什么呢
sockaddr结构
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX DomainSocket. 然而, 各种网络协议的地址格式并不相同 这些结构体中 struct sockadd_in 表示基于网络 进行网络通信的套接字 struct sockaddr_un叫做域间套接字用来两个进程之间进行本地通信的这个是取代system V本地之间进行通信的解决方案 IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16 位端口号和32位IP地址.IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.*socket API可以都用struct sockaddr 类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为 参数 U简单的UDP网络程序
udp_client.cc
#include udp_client.hppint main()
{std::cout hello client std::endl;return 0;
}udp_server.cc
#include udp_server.hpp
#include memoryusing namespace ns_server;
using namespace std;int main()
{unique_ptrUdpServer usvr(new UdpServer(1.1.1.1, 8082));usvr-InitServer(); //服务器的初始化usvr-Start();return 0;
}udp_client.hpp
#pragma once#include iostreamudp_server.hpp
#pragma once#include iostream
#include cerrno
#include cstring
#include cstdlib
#include strings.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.hnamespace ns_server
{enum{SOCKET_ERR1,BIND_ERR};const static uint16_t default_port 8080;class UdpServer{public:UdpServer(std::string ip, uint16_t port default_port): ip_(ip), port_(port){std::cout server addr: ip : port_ std::endl;}void InitServer(){// 1. 创建socket接口打开网络文件sock_ socket(AF_INET, SOCK_DGRAM, 0);if(sock_ 0){std::cerr create socket error: strerror(errno) std::endl;exit(SOCKET_ERR);}std::cout create socket success: sock_ std::endl; //3// 2. 给服务器指明IP地址(??)和Portstruct sockaddr_in local; // 这个 local 在哪里定义呢用户空间的特定函数的栈帧上不在内核中bzero(local, sizeof(local));local.sin_family AF_INET; //PF_INETlocal.sin_port htons(port_);// inet_addr: 1,2// 1. 字符串风格的IP地址转换成为4字节int, 1.1.1.1 - uint32_t - 能不能强制类型转换呢不能这里要转化// 2. 需要将主机序列转化成为网络序列local.sin_addr.s_addr inet_addr(ip_.c_str());if(bind(sock_, (struct sockaddr*)local, sizeof(local)) 0){std::cerr bind socket error: strerror(errno) std::endl;exit(BIND_ERR);}std::cout bind socket success: sock_ std::endl; //3}void Start(){}~UdpServer() {}private:int sock_;uint16_t port_;std::string ip_; // 后面要专门研究一下后面要去掉这个ip};
} // end NS_SERVER