网络编程socket

一、网络通信模式:

大部分的网络应用系统可以分为两个部分:客户(Client)和服务器(Server)

网络服务程序架构分为两种:CS模式和BS模式

CS模式:Client/Server(客户机/服务器)结构:

优点:

交互性强、具有安全的存取模式、网络通信量低、响应速度快、利于处理大量数据。

缺点:

该结构的程序是针对性开发,变更不够灵活,维护和管理的难度较大。该结构的每台客户机都需要安装相应的客户端程序,分布功能弱且兼容性差,不能实现快速部署安装和配置,因此缺少通用性,具有较大的局限性。

应用:

QQ为CS模式  需要安装客户端软件才能访问服务器。

BS模式:Browser/Server(浏览器/服务器)结构:

就是只安装维护一个服务器(Server),而客户端采用**浏览器(Browse)**运行软件。B/S结构应用程序相对于传统的C/S结构应用程序是一个非常大的进步。

优点:

分布性强、维护方便、开发简单且共享性强、总体拥有成本低。

缺点:

数据安全性问题、对服务器要求过高、数据传输速度慢、软件的个性化特点明显降低,难以实现传统模式下的特殊功能要求。例如通过浏览器进行大量的数据输入或进行报表的应答、专用性打印输出都比较困难和不便。此外,实现复杂的应用构造有较大的困难。

应用:

网站、学校教务系统等这些通过浏览器访问的模式叫BS模式。

二、OSI 七层网络模型:

应用层,表示层,会话层,传输层,网络层,数据链路层,物理层。

OSI七层网络模型,是把网络通信在逻辑上的定义,定义了通用的网络通信规范。而我们的数据在网络中传输的过程,实际上就是如下图的封装和解封装的过程,发送方通过各种封装处理,把数据转换成比特流的形式,比特流在信号传输的硬件媒介中传输,接收方再把比特流进行解封装处理。

数据的发送和接收的过程

 

三、TCP/IP协议-四层结构

1. 应用层:

 网络中的应用程序, qq, weixin , vnc,

p2p ,ftp

不同的应用程序,有不同的私有协议。

2. 传输层: (tcp, udp)

规定数据是如何传输的。

TCP协议 : transport Control Protocol 传输控制协议

他是面向连接的传输层的协议。

提供可靠性,数据无丢失,数据无失序,数据无重复(类似于打电话)。

通过"三次握手"才能建立连接

(1)Client首先向Server发送连接请求报文段,同步自己的seq(x),Client进入SYN_SENT状态。

(2)Server收到Client的连接请求报文段,返回给Client自己的seq(y)以及ack(x+1),Server进入SYN_REVD状态。

(3)Client收到Server的返回确认,再次向服务器发送确认报文段ack(y+1),这个报文段已经可以携带数据了。Client进入ESTABLISHED状态。

(4)Server再次收到Client的确认信息后,进入ESTABLISHED状态。

应答机制: 接收方收到数据时候,要应答。

什么场景会用TCP传输: ftp服务器, 对数据要求不能错,1对1。

UDP协议 : User Datagram Protocol 用户数据包协议

是不可靠的无连接的传输层协议。

不需要连接,不需要应答,数据不可靠,数据可能丢失,数据可能失序,数据可能重复(类似于发快递)

什么场景会用UDP传输: VNC ,直播 ,视频流,可以广播,可以1对多

3.网络层:(ip, icmp,igmp)

IGMP协议: Internet 组管协议。

icmp协议: Internet control message protoctl 控制报文协议

他是TCP/IP 协议组的一个子协议,用于在IP主机,路由器之间传递控制信息

IP协议: ipv4, ipv6

通过给网络上每台电脑主机分配一个 id, 用来表示这台主机====》ip地址

4. 设备驱动和硬件层

网卡, MAC地址(网卡上的物理地址,全世界唯一)标识一个网卡

如何查看:

windows: ipconfig -all

Linux:ifconfig

Inet 172.20.10.8                  ip地址

Netmark 255.255.255.240  子网掩码

Broadcast 172.20.10.15      广播地址

四、互联网地址(IP地址)

互联网上给每个接口(网卡)必须有一个唯一的Internet地址

也称为IP地址,是协议上的一个逻辑地址。 ip地址分为ipv4(32bit),ipv6(128bit)

ip地址的组成

一般我们把IPV4的地址,分为2个部分: 像日常 电话号码: 区号0731+主机号87654321

32bit = 网段号bits + 主机号bits

网段号占左边的连续的 bits

主机号占右边的连续的 bits

网段号到底占多个bits ? 由 netmask 子网掩码来决定

子网掩码由连续的 1 组成,后面跟着连续的 0。

网段号的所有位为1 主机号的所有位为0。

若一个网段的netmask为255.255.255.0

255.255.255.0 ->11111111 11111111 11111111 00000000

高24位为网段号,低8位为主机号

若设置这个网段,则最多有256-2台主机(去除IP地址和广播地址) 

255.255.255.130 ====>error netmask 是一个错误的子网掩码

(255.255.255.130->11111111.11111111.11111111.10000010  不连续)

IP地址分类:

A: 0网络号(7bit) 主机号(24bit)

网段号: 00000000 ---- 01111111

IP地址: 0.0.0.0 ----- 127.255.255.255

B: 10网络号(14bit) 主机号 (16bit)

网段号: 10000000 0000000---- 10111111 11111111

IP地址: 128.0.0.0 ----- 191.255.255.255

C: 110网络号(21bit) 主机号 (8bit)

网段号: 11000000 0000000 00000000---- 11011111

11111111 11111111

IP地址: 192.0.0.0 ----- 223.255.255.255

D: 1110网络号(28bit) D类地址主要用来进行多播和组播11100000----11101111:

224.0.0.0 --- 239.255.255.255

E: 留待后用 240.0.0.0 ---247.255.255.255

IP地址用来唯一的表示 网络中的主机

一台主机上 又有 多个 应用程序: QQ, IE, VNC,微信,腾讯视频....

发送数据到一个IP地址,他又是如何知道 发给哪个 应用程序? 端口

五、端口号

网络的通信,本质上是两个进程(应用程序)的通信。每台计算机都有很多的进程,如何区分?

IP地址唯一标识网络中的设备(主机),端口号唯一标识设备中的进程(应用程序)。

实际上通过"IP地址+端口号"来区分不同的服务的

而且,网络应用从传输层可以分为: TCP应用, UDP应用 。不同的应用程序 端口号不同:

http==== 80

ftp =====21

qq ======808

tcp的端口 和 udp端口是独立的

一台主机上的应用程序: IP地址+传输层(UDP,TCP协议)+PORT(端口号) ,利用 协议 + IP地址 + 端口号 三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。

六、字节序

大端模式:存储器的地地址存放寄存器的高字节:

网络顺序属于大端模式。

小端模式:存储器的地地址存放寄存器的低字节,

主机顺序属于小端模式

相关函数:

主机字节序转换为网络字节序的函数

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

网络字节序转换为主机字节序的函数

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

点分十进制IP地址转换为二进制IP地址函数

int inet_aton(const char *cp, struct in_addr *inp);//仅适用于ipv4

int inet_pton(int af, const char *src, void *dst);//适用于ipv4和ipv6

二进制IP地址转换为点分十进制IP地址函数

 char *inet_ntoa(struct in_addr in);

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

 

七、socket 套接字

Linux系统中,硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。为了表示和区分已经打开的文件,Linux会为每个文件分配一个ID,这个文件就是一个整数,被称为文件描述符

网络连接也是一个文件 有文件描述符为socket

socket 是一个编程接口(网络编程的API)socket 是一个特殊的文件描述符,普通的文件操作函数如: read, write同样适用于socket。

socket 接口不仅限于 TCP/IP

socket 类型:

1. 流式套接字 : SOCK_STREAM 针对于 TCP 传输层

2. 数据包套接字: SOCK_DGRAM 针对于 UDP 传输层

3. 原始套接字 : SOCK_RAW -->直接跳过传输层

Ping

八、socket 编程的流程 及 API函数

TCP 流程:

TCP server 服务器

1.创建套接字(socket)

2.将socket与IP地址和端口绑定(bind)

(如果不调用bind ,内核会分配 IP+端口号port来绑定 ,但作为 TCP服务器,必须要绑定一个

“众所周知”的端口号。好让客户端来连接你 )

3.监听被绑定的端口(listen)

4.接收连接请求(accept)

5.从socket中读取客户端发送来的信息(read)

6.向socket中写入信息(write)

7.关闭socket(close)

TCP client 客户端

1.创建套接字(socket)

2.连接指定计算机的端口(connect)

3.向socket中写入信息(write)

4.从socket中读取服务端发送过来的消息(read)

5.关闭socket(close)

UDP 流程:

UDP server 服务器:

1.使用函数socket(),生成套接字文件描述符;

2.通过struct sockaddr_in 结构设置服务器地址和监听端口;

3.使用bind() 函数绑定监听端口,将套接字文件描述符和地址类型变量(struct sockaddr_in )进行绑定;

4.接收客户端的数据,使用recvfrom() 函数接收客户端的网络数据;

5.向客户端发送数据,使用sendto() 函数向服务器主机发送数据;

6.关闭套接字,使用close() 函数释放资源;

UDP client 客户端:

1.使用socket(),生成套接字文件描述符;

2.通过struct sockaddr_in 结构设置服务器地址和监听端口;

3.向服务器发送数据,sendto() ;

4.接收服务器的数据,recvfrom() ;

5.关闭套接字,close() ;

socket API函数

1.socket()

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

参数:

domain: 协议族

AF_UNIX, AF_LOCAL Local communication 本地协议族AF_INET IPv4 Internet protocols IPV4协议

AF_INET6 IPV6协议

type: 指定套接字的类型

SOCK_STREAM 流式套接字,TCP

SOCK_DGRAM 数据报套接字, UDP

SOCK_RAW 原始套接字

protocol: 应用层协议,可以为0

返回值: 成功 返回一个 新的文件描述符  失败 -1

2.socket 地址结构:

struct sockaddr

{

sa_family_t sa_family; // 协议族== AF_INET

char sa_data[14]; // 存放 IP(4字节32bits) + PORT(2字节16bits)

}

struct sockaddr_in

{

sa_family_t sa_family; // 协议族== AF_INET

u_int16_t sin_port; // 端口号

struct in_addr sin_addr; // IPV4地址char sin_zero[8]; // 填充用的 ,为了保持与他的的协议族

的结构体大小一样

}

struct in_addr

{

in_addr_t s_addr; // ipv4 地址是 unsigned 32bits number

}

3.bind()

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数:

sockfd: 套接字描述符

struct sockaddr *addr:socket地址结构

socklen_t  addrlen: 地址的长度,一般用sizeof(struct sockaddr_in)表示

4.listen()

 int listen(int sockfd, int backlog);

参数:


sockfd:socket系统调用返回的服务端socket描述符
backlog:指定在请求队列中允许的最大的请求数,大多数系统默认为5


返回值:成功返回0,失败返回-1

5.accept()

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数:

sockfd: 套接字描述符

struct sockaddr *addr: 用来保存客户端的地址信息

socklen_t *addrlen:客户端的地址长度

返回值:连接描述符,这个连接描述符就唯一代表与一个客户端的连接。服务器后续的所有与该客户端的数据收发都通过 该描述符.

6.connect()

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

参数:

sockfd: 套接字描述符

const struct sockaddr *addr: 服务端的ip地址和端口号的地址结构指针

socklen_t addrlen: 服务器的地址长度

7.send()、recv()(TCP收发信息)

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

 参数:

sockfd:套接字描述符
buf:要发送的内容
len:发送内容的长度
flags:设置为MSG_DONTWAITMSG 时 表示非阻塞,设置为0时 功能和write一样

返回值:成功返回实际发送的字节数,失败:返回 -1

ssize_t recv(int sockfd, const void *buf, size_t len, int flags); 

参数:


sockfd:在哪个套接字接
buf:存放要接收的数据的首地址
len:要接收的数据的字节
flags:设置为MSG_DONTWAITMSG 时 表示非阻塞,设置为0时 功能和read一样

返回值:成功返回实际发送的字节数,失败:返回 -1

8.sendto()、recvfrom()函数(UDP收发信息)

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_taddrlen);

参数:

int sockfd: 发送到socket套接口描述符
const void *buf: 发送的内容的首地址
size_t len: 发送的数据的长度
flags: MSG_DONTWAIT 非阻塞, 0 默认属性(阻塞)
const struct sockaddr *dest_addr: 目的地址(ip+port)
socklen_t addrlen: 就是第五个参数(地址结构体)的长度

返回值:成功则返回发送的字节数,失败返回-1。

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

参数:

int sockfd: 从socket套接口描述符接收
void *buf: 把接收到的数据保存到 buf 指定的内存 size_t len: 最多接收 多少个 字节
int flags: 0 阻塞, MSG_DONTWAIT 非阻塞
struct sockaddr *src_addr: 会把 对方的地址IP+PORT 保存到这个结构体。
socklen_t *addrlen: 会把对方的地址结构体的长度保存到addrlen
返回值:成功则返回接收到多少个字节
-1: 失败
0 : 读完了, socket shutdown
  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值