网络编程的课程大纲

网络编程的课程大纲:
1.网络通信的基础知识;
目的:让大家对网络这块的一些概念有所了解,知道在网络中信息流是怎么传递的!===》讲解的概念和名词对接下来的网络
编程有所帮助!

1.1 网络通信的本质-从进程间通信讲起;
进程间通信方式:管道、有名管道、共享内存、消息队列、信号、信号灯、套接字!
现在的趋势是:单进程和多线程!
我电脑上的QQ给你电脑上的QQ发送消息,本质上也是进程间通信!===》这里的进程是跨越了主机,跨越了操作系统!

总结:网络通信的本质其实就是进程间通信!

1.2 网络通信的层次;
OS来操控硬件,当硬件有更新的时候,OS不知道怎么驱动这款硬件!==》OS会给硬件提供一个开发接口===》由硬件厂商
根据OS提供的开发接口开发出一款可以驱动这个硬件的驱动程序===》装上驱动程序之后,OS就可以驱动硬件!

通过刚才的讲解,要有网络分层的概念!

分层的层次:
(1)硬件层:网卡;
(2)操作系统的底层:网卡驱动;
(3)操作提供的API接口:socket接口;
(4)应用层:低级(直接基于Socket接口实现的编程); //现阶段主要学习的内容;
(5)应用层:高级(基于网络通信框架库来实现的)
  不同的架构有不同的上网手段!C++、java、安卓;
(6)应用层:更高级(http,上网控件等)

本阶段课程的要求:
1、能够明白理解我接下来要讲解的网络通信的基础知识;
2、掌握Socket及其相关的函数使用;--》重点!
3、基于Socket套接字实现的服务器和客户端!

1.3 网络通信的发展阶段;
1、单机阶段;
2、通信需求:串口通信===》RSC232==》缺点;传输速度太低,而且不方面组网;
1、局域网:就是有限台电脑进行组网连接!
2、广域网:由局域网连接而成的比较大的局域网!
3、移动互联网时代;
Fuchsia:
苹果和谷歌:

车载机:

可替代性
4、物联网阶段:所有的电子设备都可以上网;
1、智能家居;
空调:
音响:
智能锁:
2、可穿戴设备;

比较一下:上面几个的发展都是一脉相成的,对我们编程领域影响不大!

1.4 三大网络;
电信网(电信、移动、联通)、电视网络(有线电视)、互联网;
三网合一!===》现在还没有实现(利益方面的突出)!
互联网基本上已经代替了电信网和电视网络!

1.5 网络通信的传输媒介;
(1)无线传输:WiFi ZigBee 蓝牙 4G/5G/GPRS;
(2)有线传输:双绞线 光纤(传输速度快,上行和下行的速度是一样的);

1.6 OSI七层网络模型;
从下到上:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层;
(1)物理层:就是硬件---网卡;
(2)数据链路层:就是半硬件半软件;
(3)网络层、传输层、会话层、表示层、应用层:都是软件;

可以自己到网上查找具体的资料;

1.7 网络设备;
1.7.1 网卡:
1、功能:网卡是上网的设备,它是一个网卡芯片!CPU是不具备上网功能的==》借助一定的介质实现上网功能;
网卡又分为有线网卡和无线网卡;
2、网卡是一个串转并的设备:
网卡和CPU之间是并行传输数据的,而网络通信是串行全双工传输数据的;
串行:一位一位的发送数据===》传输速度比较慢===》但是适合远距离传输!
并行:8位8位的发送,也就是一个字节一个字节的发送====》传输速度比较快===》适合于短距离传输!
3、数据帧的封包和拆包的功能;
数据传输的时候不是一个字节一个字节的传送,而是以数据包的形式传送!而网卡会对数据包加上一个叠加的信息,
data:28字节!在data之前有“包头”,在data后面有“包尾”!====》存储一些必要的信息:
原因:A给B发送数据,首先要做的是找到B!==》包含一些IP地址!(精确找到!);所以还会加上一些校验位!
确保发送的数据准确无误!
校验位:13位商品条形码!
123456789_:
奇数位相加:1 + 3 + 5 + 7 + 9 = 25;
偶数位相加:2 + 4 + 6 + 8 = 20;
检验位怎么算:
1、20 * 3 + 25 = 85;
2、85对10取余:5;
3、用10 - 5 = 5;

在A端进行封包-----》在B端接收到之后,进行拆包!

4、网络数据缓存和速度匹配的功能;
也就是说网卡是协调两边的通信速度!

1.7.2 集线器;
1、功能:放大信号的作用!因为在网络传输的工程中,信号会有所衰减有所减弱===》用集线器来放大信号;
        这个时候集线器就相当于中继器的作用!
2、组建局域网:集线器里面有好几个接口,那么几台电脑插到集线器里面,然后设置同样的网段,就可以组建局域网!
3、工作方式:广播的方式!就是给每一个接口所连接的电脑都发送一个数据!====》效率比较低!
4、注意点:集线器是用来组建局域网,而不是用来连接局域网!

1.7.3 交换机;
1、交换机里面包含了集线器,但是比集线器更高级;
==》2、高级在交换机里面有MAC地址表,数据包查表后直接到达目的端口,而不是广播的方式!
因为A发送的数据包里面包含了目的主机的IP地址,所以交换机接收到数据之后,会首先到MAC地址表里面查找
ip地址所对应的端口号,如果找到直接发送过去!如果找不到,就会采用广播的方式进行查找!用广播的方式
找到之后,会将目的主机的IP地址和端口号添加到MAC地址表里面!====》学习功能!
3、找不到就广播,并且具备学习的功能!

通过价格可以看出来,交换机的功能比集线器要复杂,能买交换机就别买集线器!

1.7.4 路由器
1、路由器是局域网和外部网络连接的入口;
原因就是:每台计算机处于各自的局域网里面,然后两台之间并不能直接进行通信===》需要一个介质跨越局域网!
===》路由器横空出世!
2、路由器起到“网关”的作用!===》相当于现实生活中的“海关”!
3、路由器将整个Internet网络分隔成一个一个的局域网,但是又互相连通!
4、路由器对内管理子网(局域网),对外连接外网!
在路由器里面设置子网的网段,设置有线端口的IP地址,设置DHCP功能,因此局域网的IP地址是由路由器决定的!
路由器里面有WAN口(连接外网)和LAN口(连接内网),然后内网里面的IP地址由路由器分配!
路由器本身也是有IP地址的!
5、路由器相当于有2个网卡,一个对内做网关,一个对外做结点!
6、路由器的主要功能是为经过路由器的每个数据包寻找一个最佳路径(路由)并转发出去!
7、路由器的技术是网络中比较重要的技术,直接决定了网络的稳定性和速度!

1.8 DNS(Domain Name Service域名服务);
IP地址:192.168.1.102
DNS域名服务主要解决IP地址不方便记忆的缺陷!

1、DNS用来专门提供域名和IP地址之间转换的一个服务!
2、需要花钱购买的;
1.9 DHCP:动态主机配置协议;
每一台计算机都有唯一的IP地址,且局域网的IP地址不能够重复!否则会造成地址冲突!
IP地址的分配方式有两种:静态分配和动态分配!

1.10 NAT(Network Address Translation):网络地址转换协议;
IP地址的分类分为:外网IP和内网IP地址;
局域网里面使用的IP地址都是内网IP(常用的有192.168.XXX.XXX)
A电脑:192.168.1.100 B电脑:192.168.1.100 

情景:A(192.168.1.100)电脑要到百度上查找资料,首先把请求发给路由器(192.168.1.3),路由器会把A的IP地址
替换为路由器本身的IP地址(192.168.1.3),然后发给百度服务器!==》百度服务器把搜索的结果发给路由器。。。。

这个过程就称为NAT ==>网络地址转换协议!

NAT穿透!

1.11 IP地址的分类(IPv4)---32位!
表现形式:点分十进制(192.168.1.100)和 二进制表示

IP地址的分类:ipv4(32位)和ipv6(128位)
IP地址的组成:IP地址 = 网络地址+主机地址;
网络地址用来表示有多少个子网;
主机地址表示子网有多少个主机;

255.255.255.0 ==>前24位是1,后8位是0===》2^24个子网,2^8个主机;

怎么根据IP地址判断两台电脑是否在同一个局域网里面:
网络标识 = IP地址 & 子网掩码;===》网络标识是一样的就说明他们是在同一个子网里面;

192.168.1.102 & 255.255.255.0 = 192.168.1.0
192.168.1.100 & 255.255.0.0 = 192.168.0.0

总结:以上就是我们的网络的基础知识!

晚上:
2.网络通信编程实践;
2.1 网络编程框架;
为什么到了网络编程阶段具有分层的概念:
功能的复杂性!
功能越复杂,实现的原理也就越复杂!功能越简单,实现的原理也就越简单!

人工智能:
脑机融合:

分层的概念:OSI七层网络模型!因为七层网络模型实现起来比较复杂 ===》四层网络模型!

关于标准和具体实现!

心中要有分层的概念!

每一层都是独立的!所在什么层次只需要关心那一层就行了,不用关心其他层!

BS架构和CS架构;

CS架构:Client 和 server==>客户端和服务器架构!
A要给B发送消息:A将数据发送给===》服务器====》将数据包发送给目标客户端B!

BS架构:browser(浏览器)和 server(服务器)架构!
和CS架构相比较的话,不用下载客户端!用完关闭即可!===》微信小程序!

锡金!

TCP协议和UDP协议:
协议:计算机网络中进行数据交换的规则、标准或者是约定!
TCP协议:
1、TCP是工作在传输层的!对上服务Socket接口,对下调用IP层!
2、TCP是面向连接的,通信前必须经过三次握手协议建立连接关系,然后才能够进行通信!
跟生活中打电话之前要拨通号码是一个意思!
3、TCP协议可以提供可靠传输,不怕丢包以及乱序!

TCP是如何保证数据的可靠传输:
1、TCP在传输有效数据之前要求通信双方必须先握手,建立通信才可以进行数据传输!
2、TCP的接收在接收到数据包之后会发送ack(可以理解为“回复消息”)给发送方,如果发送方未收到ack,会重发一遍!
A给B发送数据,会有以下几种情况:
1、B没有收到A发送的消息;==》B就不会给A回复ack;===>A就不会收到ack==》A会认为数据没有发送成功===》A再发一遍;
2、B收到了A发送的消息,并且B也给A回复了ack===》ack自己丢了!==》A也会收不到ack===》A会认为数据没有发送成功
  ===》A会再发一遍数据 ====》B又收到了刚才的数据!(B就知道了ack信号在中途丢了)==》B给A回复一个ack===》
  A收到ack之后,会认为数据发送成功!

总结:丢包重传机制!保证了数据的可靠传输!
面试的时候:注意回答关键字!并且用大白话解释一遍!===》阳春白雪 又要下里巴人!

3、TCP的有效数据内容会附带校验位,防止传输过程中数据损坏!
第二点是保证接收方可以收到数据,这一点是保证接收到的数据是正确的!
A在发送的时候会附带校验位,B收到之后计算一下校验位,如果和A传过来的相同===》数据传输是正确的!

4、TCP会根据网络带宽来自动调节发送的速度===》滑动窗口技术!

也就是说会根据接收方的接收情况,自动调节每次发送多少个数据包以及每个包里面包含多少个字节!

一秒钟发10个包丢1个,一秒钟发20个包丢3个===》赚了几个;
5、发送方会给各个分隔报文加个编号;
每次发送数据的时候不是一次性发送完毕!100M的数据分10次发送,每次10M!
god dog

以上就是TCP协议保证数据传输的可靠性机制!这五点大家一定要掌握!

TCP协议三次握手!
1、服务器在Listen状态,然后等待客户端的连接====》客户端主动连接服务器,而不是服务器来连接客户端;
2、建立三次握手的过程:
1、客户端给服务器发送SYN,发送之后客户端进入到SYN_SEND状态;
2、服务器在Listen状态接收到客户端发过来的SYN之后,给客户端回复SYN+ACK,之后进入到SYN_RECEIVED状态;
3、客户端在SYN_SEND状态接收到服务器返回的SYN+ACK,之后会给服务器发送ACK,并且进入到ESTABLISED状态
然后服务器收到客户端发过来的ACK之后,进入到ESTABLISED状态;

三次握手就建立成功!


TCP四次挥手:断开连接!
注意点:客户端和服务器都可以主动发起四次挥手!

UDP协议:
面向非连接,不是可靠的,没有建立连接的过程!

小作业:什么时候使用TCP,什么时候使用UDP!【明天上课提问!】
1、对可靠性要求比较高的使用TCP协议;
2、对可靠性要求不是太高的使用UDP协议;
3、对实时性要求比较高的使用UDP;



地址结构:
1、struct sockaddr
  {
u_short sa_family; //保存协议族;如果是ipv4==》AF_INET或者是PF_INET 如果是ipv6===》AF_INET6或者是PF_INET6;
char sa_data[14]; //保存IP地址和端口号;
  };
  平时不常用,常用的是下面这个一个;
  struct sockaddr_in
  {
short int sin_family;   /* Internet地址族 */===>u_short sa_family;
unsigned short int sin_port;   /* 端口号 */
struct in_addr sin_addr;   /* IP地址 */
unsigned char sin_zero[8];     /* 填0 */
  };
  上面这个两个结构体是等价的;
  struct in_addr
  {
in_addr_t s_addr; //保存IP地址;
  };
  
一、IP地址的转化;
两种表示形式:点分十进制(192.168.1.1)和二进制之间(0xffffffff)的转化;===》本质上还是二进制来表示的;
转换函数有几下几种;
点分十进制转化为二进制:
inet_addr:只能够用于ipv4地址;
inet_aton a:ASCII  to:转换的意思  n:network
inet_pton:主要是用来兼容ipv6地址;
 
二进制转化为点分十进制:
inet_ntoa:
inet_ntop:
   
具体用法:
in_addr_t inet_addr(const char *cp); typedef u32int in_addr_t
0x1 01 a8  c0
1 1  168  192
涉及大小端的问题!
A电脑是大端模式,B电脑是小端模式:A-->B ====》主机字节序!
采用的解决方式:采用一样的存储结构!
在我们网络传输中规定,采用是大端模式!====》网络字节序!

二、主机字节序和网络字节序的转换,函数主要有一下几种!
htons;
htonl;
ntohs;
ntohl;
强调的一点:A是小端模式,===》大端模式! 如果A电脑是大端模式,网络字节序也是大端模式====》不会进行转化!
  
2.2 基于TCP和UDP的服务器和客户端的编程实现;
1、写基于TCP协议的服务器和客户端:
socket:插座!
比如:朱宇辰电脑上运行一个服务器程序,刘丽电脑上运行一个客户端程序!
服务器:
一、创建套接字:也就是调用socket函数:
二、调用bind函数进行绑定:
1、客户端要知道服务器程序运行在哪一台电脑上;(通过IP地址找到电脑)
2、在找到的电脑上再进一步找到是哪一个服务器;(通过端口号找到特定的服务器)==》端口号:就是给一个进程的编号!
陈诗学:提供江苏省(IP地址)南京市(端口号);

朱鹏:
三、Listen:设定能够连接的最大客户端数;
四、accept:监听!----》陈诗学在等待朱鹏;

客户端:
1、Socket:
2、Connect:朱鹏找陈诗学的过程;

send和recv;


API函数的介绍:
int socket(int domain, int type, int protocol);
功能:创建用于通信的套接字(插座);
参数:
domain:地址族;AF_INET / PF_INET表示的是ipv4,AF_INET6 / PF_INET6表示的是ipv6;
type:
指定通信的类型;
对于我们现阶段的常用的有SOCK_STREAM(顺序、可靠,双向,基于连接的===》用于TCP)
SOCK_DGRAM(不是基于连接的,不是可靠的===》UDP)
protocol:对于特定的套接字一般只提供一个协议,这个时候就可以把protocol赋值为0;
返回值:
成功返回文件描述符,失败返回-1;

int bind(int sockfd,const struct sockaddr *my_addr, socklen_t addrlen);
功能:为套接字绑定地址族、IP地址和端口号;
参数:
sockfd:socket函数返回的文件描述符;
my_addr:结构体指针,它指向的结构体保存地址族、IP地址和端口号;
addrlen:就是my_addr的大小;
返回值:
成功返回0,失败返回-1;

注意:(struct sockaddr *)只是防止编译警报;

int listen(int sockfd, int backlog);
功能:设置挂起队列的数量;
参数:
sockfd:.....
backlog:挂起队列的最大长度;

返回值:
成功返回0,失败返回-1;
注意点:listen只能够用于SOCK_STREAM和 SOCK_SEQPACKET=====》不能够用于SOCK_DGRAM;

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:进行监听;
参数:
sockfd:socket返回的文件描述符;
addr:用来保存客户端那边的地址族、IP地址和端口号;
addrlen:是addr的字节大小;
返回值:
成功返回一个新的文件描述符===》有客户端来连接服务器,accept会创建一个新的文件描述符来表示客户端;
例子:有A B C客户端来连接服务器,acceppt调用之后,会分别给A B C再用一个新的数字来表示,比如给A是4 ,B是5,C是6;
失败返回-1;
注意点:只能够用于基于连接的协议;===》SOCK_STREAM和 SOCK_SEQPACKET
如果没有客户端连接的时候,会阻塞在accept处!


int bind   (int  sockfd,const struct sockaddr *my_addr, socklen_t addrlen);
int connect(int  sockfd,const struct sockaddr *serv_addr, socklen_t addrlen);
功能:连接服务器;
参数:
sockfd:socket返回的文件描述符;
server_addr:保存的是要连接的服务器端的地址族、IP地址、端口号!
addrlen:就是server_addr的结构体大小;
返回值:
成功返回0,失败返回-1;

比较bind和Connect的区别:
相同点:函数参数和返回值都是一样的;
不同点:
1、功能是不一样的;bind是给服务器程序绑定所运行电脑的IP地址,以及设定端口号;connect连接另外一台电脑上的服务器
2、bind绑定的是服务器所运行的电脑(A:192.168.1.102)的IP地址,设定端口号!
  Connect在客户端调用,客户端运行在B(192.168.1.100)电脑上,因为connect是连接服务器的===》服务器由运行在
  电脑A上===》所以Connect连接的是A电脑的IP地址、端口号;而不是B电脑的IP地址和端口号!


规律:
返回值:
成功                   失败
文件描述符(socket和aeecpt) -1
0(剩余其他的) -1


服务器和客户端建立连接之后===》服务器和客户端之间进行数据交换!
发送数据:
ssize_t send(int s, const void *buf, size_t len, int flags);
     功能:向另外一个套接字发送数据;
参数:
s:套接字;
buf:用来存储要发送的数据;
len:要发送数据的大小;
flags:参照man手册里面的内容,可以用 | 操作使用多个flags;===>一般都是使用0;
返回值:
成功返回发送的字节数;失败返回-1;

ssize_t sendto(int  s,  const  void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);

send、write、sendto相比较:
1、send:用于建立连接状态的;
  sendto:既可以用于面向连接的,又可以用于面向非连接的!如果是用于面向连接的话,参数to和tolen会被忽略,也就是赋值为NULL和0;
  如果用于不是面向连接的,那么目标地址会被赋值给to和tolen!
2、send中当flags为0的时候,send = write;
    4、send(s,buf,len,0) = write(fd,buf,len) = sendto(s,buf,len,0,NULL,0);

接收数据:
ssize_t recv(int s, void *buf, size_t len, int flags);
功能:从套接字上接收数据;
参数:
s:就是accept返回的文件描述符,也就是客户端的文件描述符!
buf:用来保存数据的缓冲区;
len:保存数据的长度;
flags:参照send,一般都是设为0;
返回值:
成功返回接收到的字节大小,失败返回-1;

    ssize_t recvfrom(int s, void *buf, size_t len, int flags,struct sockaddr *from, socklen_t *fromlen);

recv、read和recvfrom之间的比较:
1、recv只能够用来基于面向连接的,而recvfrom既可以用来面向连接的,有可以用来面向非连接的;
2、当recv中的flags为0的时候,recv = read;
3、recv(s,buf,len,0) = read(fd,buf,len) = recvfrom(s,buf,len,0,NULL,NULL);
 
bind: Address already in use错误解决办法:
1、等几分钟;
2、到myhead.h中将MYPORT的值修改一下;


错误情况:
1、从客户端给服务器发送消息,现象是:服务器没有任何的反应;
  原因:printf("Recv from Client %d bytes,data:%s\n",recvcnt,recvbuff);其中的\n被删了;
2、 见现象!  
用if语句的时候要注意,是否是两个=号,然后括号后面有没有分号;
3、函数参数传多了,结构体名字写错了;



/**************************************************************************************/
基于UDP协议的服务器和客户端的实现;
服务器流程:socket-->bind-->recvfrom / sendto -->close
和TCP相比较,少了listen和accept;===>原因;
客户端流程:socket-->sendto / recvfrom --->close
和TCP相比较,少了conenct===>因为是基于非连接的;

代码演示:
修改的地方:
1、socket里面的类型由SOCK_STREAM变成SOCK_DGRAM;
2、服务器里面没有listen和accept,客户端里面没有Connect;
3、用sendto取代了sent,recvfrom代替了recv;
************************************************************************************/
演示现象:
在TCP协议下,首先用A客户端连接服务器,可以发送数据;再用客户端B来连接服务器,一方面连接不上,另一方面B给服务器
发送数据,服务器接收不到,但是如果再用A给服务器发送数据,服务器是可以收到的!

在UDP协议下,用A客户端端给服务器发送消息,服务器可以收到!再用B给服务器发送消息,服务器也可以收到的!
===》可以用多个客户端给服务器发送消息;

原因就是:我们这个程序里面的TCP服务器是“循环服务器”==》在同一个时刻只能够接收一个客户端的连接!

为了解决这个弊端,我们引入了“并发服务器”====》在同一个时刻,可以接收多个客户端的连接;
“并发服务器”的实现方式,主要有以下几种方式:
1、多进程;
  多进程的解决思路是,让一个进程只负责连接,其他的收发数据的任务,交给其他的进程来实现!
  具体解决:
用fork创建子进程,然后呢主进程里面只进行accept的连接,在子进程里面就行recv操作!

有一个客户端来连接,就创建一个子进程,再来一个客户端的连接,就再创建一个子进程;
==》每一个子进程对应一个客户端!

代码实现:
2、多线程;

3、多路IO口复用;



3.项目:基于TCP协议的即时聊天系统的项目
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值