《3.linux应用编程和网络编程-第9部分-3.9.linux网络编程实践》 inet_addr inet_ntop inet_pton htons

3.9.1.linux网络编程框架
3.9.1.1、网络是分层的
(1)OSI  7层模型 : 理论指导,7层
(2)网络为什么要分层

    网络太复杂
(3)网络分层的具体表现

    我们只研究 APP+API
3.9.1.2、TCP/IP协议引入
(1)TCP/IP协议是用的最多的网络协议实现
(2)TCP/IP分为4层,对应OSI的7层
(3)我们编程时最关注应用层,了解传输层,网际互联层和网络接入层不用管
3.9.1.3、BS和CS
(1)CS架构介绍(client server,客户端(client ) 服务器(server)架构: QQ、迅雷、)
(2)BS架构介绍(broswer server,浏览器服务器架构 : 优酷网站(不是APP)、)

3.9.2.TCP协议的学习1
3.9.2.1、关于TCP理解的重点
(1)TCP协议工作在传输层,对上服务socket接口,对下调用IP层

        
(2)TCP协议面向连接,通信前必须先3次握手建立连接关系后才能开始通信

        QQ聊天是 非 面向连接!!
(3)TCP协议提供可靠传输,不怕丢包、乱序等。
3.9.2.2、TCP如何保证可靠传输
(1)TCP在传输有效信息前要求通信双方必须先握手,建立连接才能通信
(2)TCP的接收方收到数据包后会ack(ack回应)给发送方,若发送方未收到ack会丢包重传
(3)TCP的有效数据内容会附带校验,以防止内容在传递过程中损坏
(4)TCP会根据网络带宽来自动调节适配速率(滑动窗口技术)
(5)发送方会给各分割报文编号,接收方会校验编号,一旦顺序错误即会重传。

   多个包 发送时,每个包都有编号,保证顺序不好出错

以上不用我们实现,我们只要 知道怎么使用 就行!!!

3.9.3.TCP协议的学习2
3.9.3.1、TCP的三次握手

参考:TCP协议中的三次握手和四次挥手(图解)_三次握手和四次挥手图_whuslei的博客-CSDN博客
(1)建立连接需要三次握手
(2)建立连接的条件:服务器listen时客户端主动发起connect

写 代码时,我们不会碰到这些 细节!!!

3.9.3.2、TCP的四次握手
(3)关闭连接需要四次握手
(4)服务器或者客户端都可以主动发起关闭
注:这些握手协议已经封装在TCP协议内部,socket编程接口平时不用管
3.9.3.3、基于TCP通信的服务模式
(1)具有公网IP地址的服务器(或者使用动态IP地址映射技术)

      公网数量是有限的,你有钱也不一定能容易买到, 都是使用动态IP 地址 映射技术
(2)服务器端:3个函数 socket、bind、listen后处于监听状态
(3)客户端socket后,直接connect去发起连接。
(4)服务器收到并同意客户端接入后会建立TCP连接,然后双方开始收发数据,收发时是双向的,而且双方均可发起
(5)双方均可发起关闭连接
3.9.3.4、常见的使用了TCP协议的网络应用
(1)http 应用层协议、ftp 纯传文件
(2)QQ服务器
(3)mail服务器:邮件服务器


3.9.4.socket编程接口介绍
3.9.4.1、建立连接
(1)socket。socket函数类似于open,用来打开一个网络连接,如果成功则返回一个网络文件描述符(int类型),之后我们操作这个网络连接都通过这个网络文件描述符。
(2)bind
(3)listen
(4)connect
3.9.4.3、发送和接收
(1)send和write  :都是发送
(2)recv和read    : 都是接收
3.9.4.4、辅助性函数
(1)inet_aton、inet_addr、inet_ntoa  : IP地址转换,这三函数 不支持 IPV6
(2)inet_ntop、inet_pton  :  IP地址转换 支持 IPV6

1.socket
   #include <sys/socket.h>

       int socket(int domain, int type, int protocol);

socket 函数:打开一个网络连接,成功返回一个网络文件描述符(类似于open函数)
int domain : 域 网络套接字,表示 ipv4的网络,还是ipv6 的网络 ,AF_INET :IPV4  ;    
                                AF_INET6:       IPV6                                                   
                                                    
int type :指定类型       SOCK_STREAM :TCP网络类型;  SOCK_DGRAM :UDP网络类型;


int protocol : 协议, 0表示默认协议,

返回值 -1 是错误;

2. bind 读邦德
 #include <sys/socket.h>

       int bind(int socket, const struct sockaddr *address,
              socklen_t address_len);

bind 函数:把本地的IP地址 和 socket(就是socket函数返回的网络文件描述符) 绑定起来 ,

int socket: socket 函数成功返回一个网络文件描述符(类似于open函数)
const struct sockaddr *address : 输入型参数
                   struct sockaddr,这个结构体是网络编程接口中用来表示一个IP地址的,注意这个IP        
                   地址是不区分IPv4和IPv6的(或者说是兼容IPv4和IPv6的)
socklen_t address_len : 长度

返回值 : 正确返回 0;

3. listen 读雷深 ,监听
#include <sys/socket.h>

       int listen(int socket, int backlog);

int socket :socket 函数成功返回一个网络文件描述符(类似于open函数)

int backlog : 表示可以同时 监听几个(监听队列),队列得有一个长度,设置监听队列的 长度!

返回值 : 正确返回 0;

3.1   accept  阻塞等待 客服端来连接服务器
   #include <sys/socket.h>

       int accept(int socket, struct sockaddr *restrict address,
              socklen_t *restrict address_len);


4.服务器 经过 socket 、bind 、listen ; 客户端先调用socket 就可以 来进行 连接 connect

connect 读 壳耐克特

   #include <sys/socket.h>

       int connect(int socket, const struct sockaddr *address,
              socklen_t address_len);

int socket : socket 函数成功返回一个网络文件描述符(类似于open函数)
const struct sockaddr *address :连接的 服务器 IP 地址
socklen_t address_len :
返回值 : 正确返回 0;

5.  发送数据 write
  #include <unistd.h>

      
       ssize_t write(int fildes, const void *buf, size_t nbyte);

int fildes : open函数返回的 文件描述符( socket 函数成功返回一个网络文件描述符)
const void *buf : 数据 buf
size_t nbyte :数据 长度


6. 发送数据 send 
 #include <sys/socket.h>

       ssize_t send(int socket, const void *buffer, size_t length, int flags);

int flags :如果 flags 是 0 ,就和 write 一样!
             MSG_EOR : 发一个结尾,信息的结尾(特殊协议)
             MSG_OOB : 带外数据(特殊协议)
正常通讯 用不到 flags


7. 辅助性函数  : IP 地址 转换

7.1  inet_ntop :n 网络(32位2进制), p 字符串 点分十进制

   #include <arpa/inet.h>

       const char *inet_ntop(int af, const void *src,
                             char *dst, socklen_t size);





7.2   inet_addr

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>



in_addr_t inet_addr(const char *cp);
const char *cp :  字符串 点分十进制
in_addr_t : 返回一个 typedef uint32_t in_addr_t;		网络内部用来表示IP地址的类型




7.3 inet_pton


 #include <arpa/inet.h>

 int inet_pton(int af, const char *src, void *dst);

int af : 网络IPV4 还是 IPV6 。 AF_INET :IPV4  ;    AF_INET6:   IPV6

const char *src :字符串  点分 十进制 的 IP 地址 

void *dst : 输出型参数 。如果是  IPV4 :struct in_addr  ; 如果是 IPV6:  struct in6_addr

inet_pton 函数 如果正确 返回1。


7.4 inet_ntop

#include <arpa/inet.h>

 const char *inet_ntop(int af, const void *src,
                             char *dst, socklen_t size);

int af : 网络IPV4 还是 IPV6 。 AF_INET :IPV4  ;    AF_INET6:   IPV6



8  端口号 解决 大小端 模式

 #include <arpa/inet.h>

       uint32_t htonl(uint32_t hostlong); 当前电脑 字节序 转成 网络 字节序 32位

       uint16_t htons(uint16_t hostshort); 当前电脑 字节序 转成 网络 字节序 16位

       uint32_t ntohl(uint32_t netlong);

       uint16_t ntohs(uint16_t netshort);

h : host 主机
to : 转到
n  : net 网络
l  : long  4 个字节
(3)typedef uint32_t in_addr_t;		网络内部用来表示IP地址的类型
(4)struct in_addr
  {
    in_addr_t s_addr;
  };
(5)struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;                 /* Port number.  */
    struct in_addr sin_addr;            /* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
                           __SOCKADDR_COMMON_SIZE -
                           sizeof (in_port_t) -
                           sizeof (struct in_addr)];
  };
(6)struct sockaddr			这个结构体是linux的网络编程接口中用来表示IP地址的标准结构体,bind、connect等函数中都需要这个结构体,这个结构体是兼容IPV4和IPV6的。在实际编程中这个结构体会被一个struct sockaddr_in或者一个struct sockaddr_in6所填充。

示例1  inet_addr 函数 点分十进制  IP 地址 转成  十六进制的 IP  地址

网络字节序: 其实就是 大端模式,不允许 小端模式

代码:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>



#define IPADDR "192.168.1.102"/* 字符串 点分十进制 的IP 地址 */


int main(void)
{
	
	in_addr_t addr = 0; /* typedef uint32_t in_addr_t;		网络内部用来表示IP地址的类型 */
	
	/* 字符串 点分十进制 的IP 地址 转成  uint32_t 类型的 IP 地址 */
	addr = inet_addr(IPADDR);  /* inet_addr函数返回   uint32_t 类型的 IP 地址 */
	
	printf("addr = 0x%x \n",addr);
	
	return 0;
}



运行结果:

 示例2  inet_pton 函数 :点分十进制  IP 地址 转成  十六进制的 IP  地址

代码:

#include <stdio.h>

#include <arpa/inet.h>



#define IPADDR "192.168.1.102"/* 字符串 点分十进制 的IP 地址 */


int main(void)
{
	int ret = 0; /* 定义 inet_pton 返回值  */
	
	struct in_addr addr = {0};/* 定义 inet_pton 函数的 第三个参数  */
	
	/* 字符串 点分十进制 的IP 地址 转成  uint32_t 类型的 IP 地址 */
	ret = inet_pton(AF_INET, IPADDR, &addr);  /*  */
	
	if(ret!= 1)
	{
		printf("inet_pton error \n");
		return -1;
	}
	
	printf("addr.s_addr = 0x%x \n",addr.s_addr);
	
	return 0;
}

/*************************

addr.s_addr 是从哪里来的???

答:
typedef uint32_t in_addr_t;		网络内部用来表示IP地址的类型
struct in_addr
{
   in_addr_t s_addr;
};

*************************/

运行结果:

 示例3   inet_ntop 函数 :十六进制的 IP  地址  转成   点分十进制  IP 地址

#include <stdio.h>
#include <arpa/inet.h>



int main(void)
{
	const char* ret = NULL ; /* 定义 返回值 ,当一个函数的 返回值 是cost时, 我们定义的 返回值也要加 const  */
	char buf[50]= {0};
	struct in_addr addr = {0};/*   */
	addr.s_addr = 0x6601a8c0 ;/* 定义 uint32_t 类型的 IP 地址   */

	
	/* 把 uint32_t 类型的 IP 地址 转成  字符串 点分十进制 的IP 地址   */
	ret = inet_ntop(AF_INET,&addr,buf,sizeof(buf));  /*  */
	
	if(ret == NULL)
	{
		printf("inet_ntop error \n");
		return -1;
	}
	
	printf("buf = %s \n",buf);
	
	return 0;
}

/*************************

addr.s_addr 是从哪里来的???

答:
typedef uint32_t in_addr_t;		网络内部用来表示IP地址的类型
struct in_addr
{
   in_addr_t s_addr;
};

*************************/

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大漠飞鹰6666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值