Linux——网络基础socket套接字(协议、协议模型、IP、Port、网络字节序...

Linux——网络基础socket套接字(协议、协议模型、IP、Port、网络字节序...

2023年7月15日发(作者:)

Linux——⽹络基础socket套接字(协议、协议模型、IP、Port、⽹络字节序)协议协议是指通信双⽅约定使⽤同⼀种解析信息的⼿段来进⾏有效的沟通协议分层模型OSI参考模型(⾃下⽽上):物理层、数据链路层、⽹络层、传输层、会话层、表⽰层、应⽤层TCP/IP五层(或四层)模型TCP/IP是⼀组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇.TCP/IP通讯协议采⽤了5层的层级结构,每⼀层都呼叫它的下⼀层所提供的⽹络来完成⾃⼰的需求。1. 物理层:负责光/电信号的传递⽅式. 物理层的能⼒决定了最⼤传输速率、传输距离、抗⼲扰性等. 集线器(Hub)⼯作在物理层.2. 数据链路层: 负责相邻设备之间的数据帧传输和识别. 例如⽹卡设备的驱动、帧同步(就是说从⽹线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就⾃动重发)、数据差错校验等⼯作. 有以太⽹、令牌环⽹, ⽆线LAN等标准. 交换机(Switch)⼯作在数据链路层.3. ⽹络层: 负责地址管理和路由选择. 例如在IP协议中, 通过IP地址来标识⼀台主机, 并通过路由表的⽅式规划出两台主机之间的数据传输的线路(路由). 路由器(Router)⼯作在⽹路层.4. 传输层: 负责两台主机之间的数据传输. 如传输控制协议 (TCP), 能够确保数据可靠的从源主机发送到⽬标主机.5. 应⽤层: 负责应⽤程序之间的数据沟通,为操作系统或⽹络应⽤程序提供访问⽹络服务的接⼝,如简单电⼦邮件传输(SMTP)、⽂件传输协议(FTP)、⽹络远程访问协议(Telnet)等.数据传输的封装与分⽤不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在⽹络层叫做数据报 (datagram),在链路层叫做帧(frame).应⽤层数据通过协议栈发到⽹络上时,每层协议都要加上⼀个数据⾸部(header),称为封装IP地址作⽤:标定全公⽹内唯⼀台主机。本质:⽆符号32位整型,4个字节192.168.1.1——>点分⼗进制表⽰法点分法每⼀个字节最⼤能够表⽰的数字是255源IP地址和⽬的IP地址源IP:src_ip——>标识数据从哪⾥来⽬的IP:dest_ip——>表⽰数据往哪⾥去port端⼝号port:标定特定⼀台主机上的唯⼀⼀个进程。端⼝号是⼀个2字节16位的整数。⽤来标识⼀个进程, 告诉操作系统, 当前的这个数据要交给哪⼀个进程来处理。ip地址+端⼝号能够标识全⽹某⼀台主机的某⼀个进程。⼀个端⼝号只能被⼀个进程占⽤。理解 “端⼝号” 和 “进程ID”:1. 端⼝号是⽹络进程的标识。2. ⼀个进程可以绑定多个端⼝号; 但是⼀个端⼝号不能被多个进程绑定。⽹络字节序字节序:CPU对内存的访问顺序⼤端字节序:低地址存⾼位⼩段字节序:低地址存低位TCP/IP协议规定,⽹络数据流应采⽤⼤端字节序,即低地址⾼字节。⼩段机器和⼤端机器进⾏⽹络通信的时候,需要转换字节序。主机字节序:当前机器的字节序。字节序转换:为使⽹络程序具有可移植性,使同样的C代码在⼤端和⼩端计算机上编译后都能正常运⾏,可以调⽤以下库函数做⽹络字节序和主机字节序的转换。h表⽰host,n表⽰network,l表⽰32位长整数,s表⽰16位短整数1.将32位的主机字节序转换为⽹络字节序uint32_t htonl(uint32_t hostlog);2.将32位的⽹络字节序转换为主机字节序uint32_t ntohl(uint32_t netlog);3.将16位的主机字节序转换为⽹络字节序uint16_t htons(uint16_t hostshort);4.将16位的⽹络字节序转换为主机字节序uint16_t ntohs(uint16_t netshort);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结构IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址⽤sockaddr_in结构体表⽰,包括16位地址类型, 16位端⼝号和32位IP地址。IPv4、 IPv6地址类型分别定义为常数AF_INET、 AF_INET6。socket API可以都⽤struct sockaddr *类型表⽰, 在使⽤的时候需要强制转化成sockaddr_in; 这样的好处是统⼀接⼝(程序的通⽤性), 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。sockaddr 结构查看soackaddr内部:虽然socket api的接⼝是sockaddr, 但是我们真正在基于IPv4编程时, 使⽤的数据结构是sockaddr_in; 这个结构⾥主要有三部分信息: 地址类型, 端⼝号, IP地址。简单的UDP⽹络程序实现⼀个简单的英译汉的功能。Server端代码:#pragma once

#include #include #include #include #include #include #include #include #include #include class udpServer{ private: //std::string ip; int port;//端⼝号 int sock; std::map dict; public: udpServer(int _port = 8080) :port(_port) { (std::pair("apple", "苹果")); (std::pair("banana", "⾹蕉"));

(std::pair("student", "学⽣")); }

void initServer() { sock = socket(AF_INET, SOCK_DGRAM, 0); std::cout << "sock: " << sock << std::endl; struct sockaddr_in local;//内核层 _family = AF_INET;//协议家族IPV4 _port = htons(port); //_addr.s_addr = inet_addr(ip.c_str()); _addr.s_addr = INADDR_ANY; if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0) { std::cerr << "bind error!n" << std::endl; exit(1); }

}

//echo server

void start() { char msg[64]; for(;;) { msg[0] = '0'; struct sockaddr_in end_point;//远端 socklen_t len = sizeof(end_point); ssize_t s = recvfrom(sock, msg, sizeof(msg)-1, 0, (struct sockaddr*)&end_point, &len); if(s > 0) { char buf[16]; sprintf(buf, "%d", ntohs(end__port)); std::string cli = inet_ntoa(end__addr); cli += ":"; cli += buf; msg[s] = '0'; std::cout << cli << "# " << msg << std::endl; std::string echo = "unknow"; auto it = (msg); if(it != ()) { echo = dict[msg]; } //echo_str += " [server echo!]"; sendto(sock, echo.c_str(), (), 0, (struct sockaddr*)&end_point, len); } } }

~udpServer() { close(sock); }};Client端代码:#pragma once

#include #include #include #include #include #include #include #include class udpClient{ private: std::string ip; int port;//端⼝号 int sock; public: //ip,port

填服务器的 udpClient(std::string _ip = "127.0.0.1", int _port = 8080) :ip(_ip),port(_port) {

}

void initClient() { sock = socket(AF_INET, SOCK_DGRAM, 0); std::cout << "sock: " << sock << std::endl; }

//echo server

void start() { //char msg[64]; std::string msg; struct sockaddr_in peer; _family = AF_INET; _port = htons(port); _addr.s_addr = inet_addr(ip.c_str()); for(;;) { std::cout << "Please Enter# "; std::cin >> msg; if(msg == "quit") { break; } sendto(sock, msg.c_str(), (), 0, (struct sockaddr*)&peer, sizeof(peer));

char echo[128]; ssize_t s = recvfrom(sock, echo, sizeof(echo)-1, 0, nullptr, nullptr); if(s > 0) { echo[s] = '0'; std::cout << "server# " << echo << std::endl; }

} }

~udpClient() { close(sock); }};

发布者:admin,转转请注明出处:http://www.yc00.com/web/1689409675a243460.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信