1、管道
无名管道 (只能作用于亲缘间进程通信) ----pipe write read
有名管道 (系统中任意两个进程) -----mkfifo
2、信号
发送信号 ---kill
捕捉信号----signal
3、IPC对象
消息队列 ----带有数据标识的特殊管道 ftok() msgget msgsnd msgrcv msgctl
共享内存 ----双方进程 可以同时 对一片内存进行读写 ftok shmget shmat shmdt
信号量 ------不属于通信方式,只是一种互斥的方式 ftok semget semop semctl
特点:只能在同一台主机上内部通信,不能跨平台。
1、特点
既可以在同一台主机上内部通信,还可以在不同主机之间通信。
自己的ubuntu ---- 自己的ubuntu
自己的ubuntu ---- 同一个局域网内除了自己之外的任意一台主机
总结: 网络通信的前提是 在同一个局域网内。
2、协议
在不同的主机之间通信,双方都必须遵循的同一种规则。
阿帕网(arpanet)
使用协议:网络控制协议(NCP) Network Control Program
缺点:不能互联不同类型的计算机 和 不同类型的操作系统,同时也没有纠错功能
因特网(Internet)
由于阿帕网(arpanet)的局限,所以在其基础上扩展 研发出了 因特网(Internet),并且引入了TCP/IP协议。TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
TCP/IP协议:传输控制协议/网际协议 。
TCP协议: 用于检测网络中传输差错
IP协议: 负责不同的网络之间的通信。
也就是说,TCP主要是负责 数据的传输问题,一旦有问题发出信号,要求重新传输,直到数据安全到达为止。IP给每一台主机分配一个IP地址。
1、概念
指的是 主机内部集成的结构和各层协议的集合。
每台主机本身就存在一个相同的网络体系结构。
2、作用
封装数据 和 解析数据
3、分类
ISO/OSI参考模型
TCP/IP参考模型
OSI从逻辑上,把一个网络系统分为功能上相对独立的7个有序的子系统,这样OSI体系结构就由功能上相对独立的7个层次组成,如图1所示。它们由低到高分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
应用层:确定这个数据应该以什么样的API接口 进行处理
表示层:数据的压缩和解压、加密和解密这些工作都是由表示层完成的。
会话层:访问验证,通信之前建立TCP会话
传输层:控制 和 检测 数据传输过程中是否出错,TCP协议 、UDP协议
网络层:主要是IP协议,识别网络中不同的主机
数据链路层:1、将数据组合成数据块,也就是一帧帧数据(给数据块添加数据头和数据尾)
物理层:承担数据传输的物理媒体(通信的通道),以太网口
1、层次
应用层: Telnet FTP HTTP
传输层: TCP UDP
网际层: IP ICMP
网络接口层:以太网
2、每经过一层,会一层层添加头数据,当数据到达对方时,会一层层解析头数据
3、在上面模型中 ,传输层协议: TCP协议 、UDP协议(重点)
1、概念
用来检测网络传输中差错的传输控制协议 (TCP,Transmission Control Protocol)。是一种面向连接的传输层协议,它能够提供高可靠性通信(也就是 数据 无误、数据无丢失、数据无失序、数据无重复到达的通信)
2、应用场合
1)对传输质量要求高、以及传输大量数据的通信
2)在需要可靠性数据传输的场合,通常使用TCP协议
3)QQ等 通信软件的用户登录账号管理 的功能,采用TCP
1、概念
用户数据报协议(UDP,User Datagram Protocol)。是一种不可靠、没有连接的协议。在数据发送之前,因为不需要进行连接,所以可以进行高效率的数据传输。
2、应用场合
1)发送小尺寸数据
2) 适用于 广播 /组播 通信
3)qq等通讯 软件中 点对点 文本通信 以及音视频
插座、套接字 插座的种类比较多,就像很多个协议一样,必须提前设置好协议
1)是一个编程的函数接口,建立套接字
2)不管你是使用TCP协议 还是 用 UDP协议,首先必须使用socket进行确定
比如: 我们现在使用TCP协议
套接字文件描述符 socketfd = socket(TCP协议);
普通文件 : int fd = open(文件的名字);---》
3)套接字 是一种 特殊的 文件描述符
1、概念
用来标识 网络中不同的主机。通信的前提必须要有一个IP地址
2、分类
IPV4地址 ---32位 IPV6地址 --128位
3、如何表示
点分十进制 "192.168.14.2" 网络号(网段 192.168.14) + 主机号(2)
4、数据包中 都必须要包含 目的IP地址、源IP地址。
1、概念
标识 同一台主机内不同的应用程序。
网络
主机A ---------------- 主机B
qq qq
微信 微信
soul “想你了,宝” soul
192.168.14.2 192.168.14.5 ---必须在同一个局域网
“想你了,宝” + 192.168.14.2 + 192.168.14.5 + 50000
端口号:
1)系统占用端口号: 1-1023(用户不能再次使用这些端口号进行通信)
2) 可用端口号:1024~65535
端口号错误 ---》连接错误
1)、概念
一个多字节存储单元的低地址 存储数据的高有效位 还是 低有效位 ,说白了,也就是说 数据 在计算机内存中以什么样的方式存储
2)分类
小端序:数据的低有效位 存储 在 内存的 低地址
大端序:数据的低有效位 存储 在 内存的 高地址
3)为了避免不同类别的主机之间 在数据交换时由于字节序的不同导致的差错,引入了网络字节序。也就是说统一规定所有的主机通过网络发送数据包时转为 大端序 ,也就是网络字节序。
网络字节序---》一定是大端序。
本地字节序---》取决于 主机 x86是小端 ARM是大端
总结: 无论当前你的主机是大端 还是 小端,都必须把自身的字节序 转成 网络字节序,即大端序,才能在网络中传输数据。
window: 192.168.14.2
ubuntu: 192.168.14.3
开发板:192.168.14.4
在ubuntu中 :
1、ifconfig --查看IP 获取 网卡名字
ubuntu12.04 eth0
ubuntu18.04 ens33
2、配置
ifconfig eth0 192.168.14.3
3、ubuntu与window进行ping连接
ping 192.168.14.2(window)
gec@ubuntu:/mnt/hgfs/gz2166/00C习题/2021.10.28笔试题/043广东华中科技大学工业
��术研究院$ ping 192.168.14.2
PING 192.168.14.2 (192.168.14.2) 56(84) bytes of data.
64 bytes from 192.168.14.2: icmp_req=1 ttl=128 time=0.299 ms
64 bytes from 192.168.14.2: icmp_req=2 ttl=128 time=0.240 ms
64 bytes from 192.168.14.2: icmp_req=3 ttl=128 time=0.195 ms
客户端通信:
1、买手机(建立套接字)
#include
#include
int socket(int domain, int type, int protocol);
函数作用:建立套接字
参数:
domain:你要选择哪一种地址族
PF_INET/AF_INET ------Ipv4 网络协议
PF_INET6/AF_INET6----- Ipv6 网络协议
type: 你要选择哪一种 协议(TCP UDP)
SOCK_STREAM --流式套接字 TCP
SOCK_DGRAM -数据报套接字 UDP
protocol:一般设置成 0
返回值:
成功返回 套接字文件描述符
失败 -1
2、绑定自己的电话号码(绑定自己的IP地址 和端口号)
#include
#include
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:
sockfd:套接字文件描述符
addr:自己的IP地址和端口号
addrlen:结构体的大小
返回值 :
成功则返回 0,
失败返回-1, 错误原因存于 errno 中
struct sockaddr --旧的结构体
{
unsigned short sa_family; /*地址族*/
char sa_data[14];/*14字节的协议地址,包含该socket的IP地址和端口号。*/
};
//IPV4结构体
struct sockaddr_in
{
short int sin_family; /*地址族 IPV4 IPV6*/
unsigned short int sin_port; /*端口号*/
struct in_addr sin_addr; /*IP地址*/
unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/
};
struct in_addr {
in_addr_t s_addr; /*in_addr_t为 32位的unsigned int,该无符号整数采用大端字节序。*/
};
扩展函数:
1、将本地IP地址转为网络IP地址
in_addr_t inet_addr(const char *cp);
参数:
cp:本地IP地址
返回值: 返回网络IP地址
3、开始打电话(发起连接)
#include
int connect(int socket, const struct sockaddr *address,socklen_t address_len);
参数:
sockfd:套接字文件描述符
address:对方的IP地址和端口号
address_len:结构体的大小
4、聊天
#include
ssize_t send(int socket, const void *buffer, size_t length, int flags);
参数:
sockfd:套接字文件描述符
buffer:你要发送的数据
length:你要发送的数据大小 strlen
flags: 一般为0
返回值:
成功返回 发送的数据字节数
失败返回 -1
5、关闭
close(socketfd);
服务器 :
3、设置铃声(监听)
#include
int listen(int socket, int backlog);
参数:
sockfd:套接字文件描述符
backlog:同时支持 最多的客户端连接个数
4、坐等电话(阻塞接收客户端的连接)
#include
int accept(int socket, struct sockaddr * address,socklen_t * address_len);
参数:
sockfd:套接字文件描述符
address:存储已经连接上来的客户端的IP地址和端口号 ,如果不关系客户端的IP地址和端口号,可以设置成NULL
address_len:结构体的大小
返回值:
成功返回 已经连接上来的新的客户端的套接字文件描述符
失败返回 -1
#include
#include
#include
in_addr_t inet_addr(const char *cp);
函数作用:
将本地IP地址转为网络IP地址
参数:
cp:本地IP地址
返回值:返回网络IP地址 ,注意是 in_addr_t
char *inet_ntoa(struct in_addr in); //n 网络 a 本地
函数作用:
将网络IP地址 转为本地IP地址
参数:
in:网络IP地址 注意是 struct in_addr 类型
返回值:
本地IP地址
#include
uint16_t htons(uint16_t hostshort); //h表示本地 n表示网络 s表示 unsigned short int 16
函数作用:将本地端口号转为网络端口号
参数:
hostshort 本地端口号
返回值:
返回网络端口号
uint16_t ntohs(uint16_t netshort);
函数作用:将网络端口号转为本地端口号
参数:
netshort 网络端口号
返回值:
返回本地端口号
#include
#include
#include /* See NOTES */
#include
#include
#include
#define OWNADDR "192.168.14.3" //我自己电脑的ip地址
#define OWNPORT 10000 //我自己电脑的该程序的端口号
#define SERVERADDR "192.168.14.3" //对方的 服务器的IP地址
#define SERVERPORT 20000 //对方的 服务器的端口号
int main()
{
//1、买手机(建立套接字)
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
if(socketfd == -1)
{
printf("没钱了....,失败\n");
return -1;
}
//2、绑定自己的电话号码(绑定自己的IP地址 和端口号)
//定义一个IPV4结构体变量,初始化自己的IP地址和端口号
struct sockaddr_in ownAddr;
ownAddr.sin_family = AF_INET;/*地址族 IPV4*/
ownAddr.sin_port = htons(OWNPORT); //htons 将本地端口号转为网络端口号
ownAddr.sin_addr.s_addr = inet_addr(OWNADDR); //将本地IP地址转为网络IP地址
bind(socketfd, (struct sockaddr *)&ownAddr,sizeof(struct sockaddr_in));
//3、开始打电话(发起连接)
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;/*地址族 IPV4*/
serverAddr.sin_port = htons(SERVERPORT); //htons 将本地端口号转为网络端口号
serverAddr.sin_addr.s_addr = inet_addr(SERVERADDR); //将本地IP地址转为网络IP地址
connect(socketfd,(struct sockaddr *)&serverAddr,sizeof(struct sockaddr_in));
//4、聊天
while(1)
{
printf("data:");
char buf[1024]={0};
scanf("%s",buf);
//发送数据
send(socketfd, buf, strlen(buf), 0);
}
//5、关闭
close(socketfd);
return 0;
}
#include
#include
#include /* See NOTES */
#include
#include
#include
#define OWNADDR "192.168.14.3" //我自己电脑的ip地址
#define OWNPORT 20000 //我自己电脑的该程序的端口号
int main()
{
//1、买手机(建立套接字)
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
if(socketfd == -1)
{
printf("没钱了....,失败\n");
return -1;
}
//因为服务器立马退出之后,端口号不会及时释放
//此时如果服务器又马上运行,那么端口号会被占用,导致服务器分配端口号失败,连接失败
//所以设置端口号可以复用
int optval = 1;
setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,&optval, sizeof(optval));
//2、绑定自己的电话号码(绑定自己的IP地址 和端口号)
//定义一个IPV4结构体变量,初始化自己的IP地址和端口号
struct sockaddr_in ownAddr;
ownAddr.sin_family = AF_INET;/*地址族 IPV4*/
ownAddr.sin_port = htons(OWNPORT); //htons 将本地端口号转为网络端口号
ownAddr.sin_addr.s_addr = inet_addr(OWNADDR); //将本地IP地址转为网络IP地址
bind(socketfd, (struct sockaddr *)&ownAddr,sizeof(struct sockaddr_in));
//3、设置铃声(监听) listen
listen(socketfd,5);
//4、坐等电话(阻塞接收客户端的连接)
printf("等待客户端连接.......\n");
//定义一个IPV4结构体变量,存储连接上来的客户端的IP地址 和 端口号
struct sockaddr_in clientAddr;
//如果你要想要获取对方的IP地址和端口号,第三个参数必须把结构体的大小传递进去
int len = sizeof(struct sockaddr_in);
int newClientFd = accept(socketfd,(struct sockaddr*)&clientAddr,&len);
if(newClientFd != -1)
{
printf("有客户端连接上来了............\n");
//打印连接上来的客户端的IP地址和端口号,将网络字节序转为 本地字节序
printf("连接上来的客户端IP:%s 端口号:%u\n",inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port));
}
while(1)
{
char buf[1024]={0};
//重点重点重点:recv 一定是使用 已经连接上来的新客户端的套接字文件描述符 newClientFd
int ret = recv(newClientFd,buf,sizeof(buf),0);
if(ret == 0)//代表客户端退出
{
printf("客户端退出.....\n");
break;
}
printf("recv:%s\n",buf);
}
//5、关闭
close(socketfd);
close(newClientFd);
return 0;
}
#include
#include
int setsockopt(int s, int level, int optname, const void * optval, , socklen_toptlen);
函数作用:设置端口号可以复用
参数:
s:套接字文件描述符
level 代表欲设置的网络层, 一般设成 SOL_SOCKET 以存取 socket 层
optname:SO_REUSEADDR 端口号复用
optval 代表欲设置的值, 比如给它一个1
optlen 则为 optval 的长度.
//所以设置端口号可以复用,这两条语句放在 绑定bind 之前
int optval = 1;
setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,&optval, sizeof(optval));
#include
#include
#include /* See NOTES */
#include
#include
#include
#include
#define OWNADDR "192.168.14.3" //我自己电脑的ip地址
#define OWNPORT 10000 //我自己电脑的该程序的端口号
#define SERVERADDR "192.168.14.3" //对方的 服务器的IP地址
#define SERVERPORT 20000 //对方的 服务器的端口号
void * start_routine(void *arg)
{
int socketfd = *((int*)arg);//强转类型 并且解引用 得到socketfd
//接收服务器的数据
while(1)
{
char buf[1024]={0};
int ret = recv(socketfd,buf,sizeof(buf),0);
if(ret == 0)
break;
printf("recv:%s\n",buf);
}
pthread_exit(NULL);
}
int main()
{
//1、买手机(建立套接字)
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
if(socketfd == -1)
{
printf("没钱了....,失败\n");
return -1;
}
//2、绑定自己的电话号码(绑定自己的IP地址 和端口号)
//定义一个IPV4结构体变量,初始化自己的IP地址和端口号
struct sockaddr_in ownAddr;
ownAddr.sin_family = AF_INET;/*地址族 IPV4*/
ownAddr.sin_port = htons(OWNPORT); //htons 将本地端口号转为网络端口号
ownAddr.sin_addr.s_addr = inet_addr(OWNADDR); //将本地IP地址转为网络IP地址
bind(socketfd, (struct sockaddr *)&ownAddr,sizeof(struct sockaddr_in));
//3、开始打电话(发起连接)
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;/*地址族 IPV4*/
serverAddr.sin_port = htons(SERVERPORT); //htons 将本地端口号转为网络端口号
serverAddr.sin_addr.s_addr = inet_addr(SERVERADDR); //将本地IP地址转为网络IP地址
connect(socketfd,(struct sockaddr *)&serverAddr,sizeof(struct sockaddr_in));
//创建一条线程,接收服务器的数据
pthread_t thread;
pthread_create(&thread,NULL,start_routine,&socketfd);
//4、聊天
while(1)
{
printf("data:");
char buf[1024]={0};
scanf("%s",buf);
//发送数据
send(socketfd, buf, strlen(buf), 0);
}
//5、关闭
close(socketfd);
//接合线程 --阻塞等待子线程退出,回收资源
pthread_join(thread,NULL);
return 0;
}
#include
#include
#include /* See NOTES */
#include
#include
#include
#include
#define OWNADDR "192.168.14.3" //我自己电脑的ip地址
#define OWNPORT 20000 //我自己电脑的该程序的端口号
void * start_routine(void *arg)
{
int newClientFdfd = *((int*)arg);//强转类型 并且解引用 得到socketfd
//给客户端发送数据
while(1)
{
printf("data:");
char buf[1024]={0};
scanf("%s",buf);
//发送数据
send(newClientFdfd, buf, strlen(buf), 0);
}
pthread_exit(NULL);
}
int main()
{
//1、买手机(建立套接字)
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
if(socketfd == -1)
{
printf("没钱了....,失败\n");
return -1;
}
//因为服务器立马退出之后,端口号不会及时释放
//此时如果服务器又马上运行,那么端口号会被占用,导致服务器分配端口号失败,连接失败
//所以设置端口号可以复用
int optval = 1;
setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,&optval, sizeof(optval));
//2、绑定自己的电话号码(绑定自己的IP地址 和端口号)
//定义一个IPV4结构体变量,初始化自己的IP地址和端口号
struct sockaddr_in ownAddr;
ownAddr.sin_family = AF_INET;/*地址族 IPV4*/
ownAddr.sin_port = htons(OWNPORT); //htons 将本地端口号转为网络端口号
ownAddr.sin_addr.s_addr = inet_addr(OWNADDR); //将本地IP地址转为网络IP地址
bind(socketfd, (struct sockaddr *)&ownAddr,sizeof(struct sockaddr_in));
//3、设置铃声(监听) listen
listen(socketfd,5);
//4、坐等电话(阻塞接收客户端的连接)
printf("等待客户端连接.......\n");
//定义一个IPV4结构体变量,存储连接上来的客户端的IP地址 和 端口号
struct sockaddr_in clientAddr;
//如果你要想要获取对方的IP地址和端口号,第三个参数必须把结构体的大小传递进去
int len = sizeof(struct sockaddr_in);
int newClientFd = accept(socketfd,(struct sockaddr*)&clientAddr,&len);
if(newClientFd != -1)
{
printf("有客户端连接上来了............\n");
//打印连接上来的客户端的IP地址和端口号,将网络字节序转为 本地字节序
printf("连接上来的客户端IP:%s 端口号:%u\n",inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port));
}
//创建一条线程,给客户端发送数据
//注意 使用的是 连接上来的客户端的新的套接字文件描述符newClientFd
pthread_t thread;
pthread_create(&thread,NULL,start_routine,&newClientFd);
while(1)
{
char buf[1024]={0};
//重点重点重点:recv 一定是使用 已经连接上来的新客户端的套接字文件描述符 newClientFd
int ret = recv(newClientFd,buf,sizeof(buf),0);
if(ret == 0)//代表客户端退出
{
printf("客户端退出.....\n");
break;
}
printf("recv:%s\n",buf);
}
//5、关闭
close(socketfd);
close(newClientFd);
//接合线程 --阻塞等待子线程退出,回收资源
pthread_join(thread,NULL);
return 0;
}