网络的基本概念
1.协议
1.1 协议的基本概念
1.2 常见的协议
2.分层模型
2.1网络七层OSI 7层模型:物数网传会表应(口诀)
应用层:为客户提供各种应用服务,email服务,ftp服务,ssh服务。
表示层:编解码,翻译工作。
会话层:通过传输层建立数据传输的通道,建立,维护,终止会话。
传输层:传输数据,TCP,UDP协议,端对端传输。
网络层:定义了网络,两台机器之间的传输路径选择点对点传输。
数据链路层(网络接口层):数据校验,定义了网络传输的基本单位–帧。
物理层:双绞线,光纤(传输介质),将模拟信号信号转化为数字信号。
2.2TCP/IP模型
2.3数据通信的过程
在数据发送方是一个层层打包的过程,数据接收方是一个层层解包的过程。
2.4网络的设计模式
网络的设计模式,有B/S模式和C/S模式。
硬件环境要求:C/S 用户固定,一般只应用于局域网中,要求拥有相同的操作系统,如果对于不同操作系统还要相应开发不同的版本,并且对于计算机电脑配置要求也较高。
硬件环境要求:要求有操作系统和浏览器就行,与操作系统平台无关(可以实现跨平台),对客户端的计算机电脑配置要求较低。
2.5以太网帧的格式
这里的目的地址和源地址都是指MAC地址,MAC地址为6个字节,IP地址为4个字节,不同类型对应了不同的值,CRC是进行校验的。
下面我们我们来以ARP请求包,假如我们有狠多的机器,我们想给其中一个机器建立对话,我们不知道它的MAC地址只知道IP地址,那么我们如何建立会话呢?
现在我们来看看以太网帧,以ARP为例。
这里是ARP请求包,不知道的mac地址我们填ff:ff:ff:ff:ff:ff。
如果这个IP地址和自己一样,给A机器发一个ARP应答包。
3.SOCKET编程
3.1网络字节序
socket编程之前,我们要知道大端字节序和小端字节序是什么意思
如何知道我们的程序是大端字节序还是小端字节序呢?可以通过下面这个代码
#include <stdio.h>
union{
char byte[4];
int num;
}test;
int main()
{
test.num=0x12345678;
if(test.byte[0]==0x78)
printf("小端\n");
else if(test.byte[0]==0x12)
printf("大端\n");
else
printf("error");
printf("[0]:%p:0x%X\n"
"[1]:%p:0x%X\n"
"[2]:%p:0x%X\n"
"[3]:%p:0x%X\n",
&test.byte[0], test.byte[0],
&test.byte[1], test.byte[1],
&test.byte[2], test.byte[2],
&test.byte[3], test.byte[3]);
return 0;
}
我们在网络传输的时候用的是网络字节序,也就是大端字节序,进行网络通信时要把地址转化为大端字节序,下面是相关函数。
把点分十进制转化为大端字节序IP
把大端字节序IP转化为点分十进制IP
3.2 相关结构体和函数
常用的结构体sockaddr,我们一般用第二个结构体,方便我们赋值
这是我们用的socket函数
下面是它的参数说明
成功以后会返回文件描述符
然后就是bind函数,用来给客户端和服务器端建立联系。
下面把客户端由注动变为监听状态(客户端主动连接服务器)
得到一个连接,进行客户端和服务端之间的通信
这里我们就用知道,accept是一个阻塞函数,它要从已连接队列中拿一个可用的连接过来。调用accept之前连接可能就已经建立了。
现在就可以连接服务器了,用connect函数
3.3 代码实现
服务端的开发
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>
int main()
{
//创建socket
//int socket(int domain, int type, int protocol);
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd<0)
{
perror("socket error");
return -1;
}
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//绑定
struct sockaddr_in serv;
bzero(&serv, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(8888);
serv.sin_addr.s_addr = htonl(INADDR_ANY); //表示使用本地任意可用IP
int ret = bind(lfd, (struct sockaddr *)&serv, sizeof(serv));
if(ret<0)
{
perror("bind error");
return -1;
}
//监听
//int listen(int sockfd, int backlog);
listen(lfd, 128);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
struct sockaddr_in client;
socklen_t len = sizeof(client);
int cfd = accept(lfd, (struct sockaddr *)&client, &len); //len是一个输入输出参数
//const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
//获取client端的IP和端口
char sIP[16];
memset(sIP, 0x00, sizeof(sIP));
printf("client-->IP:[%s],PORT:[%d]\n", inet_ntop(AF_INET, &client.sin_addr.s_addr, sIP, sizeof(sIP)), ntohs(client.sin_port));
printf("lfd==[%d], cfd==[%d]\n", lfd, cfd);
int i = 0;
int n = 0;
char buf[1024];
while(1)
{
//读数据
memset(buf, 0x00, sizeof(buf));
n = read(cfd, buf, sizeof(buf));
if(n<=0)
{
printf("read error or client close, n==[%d]\n", n);
break;
}
printf("n==[%d], buf==[%s]\n", n, buf);
for(i=0; i<n; i++)
{
buf[i] = toupper(buf[i]);
}
//发送数据
write(cfd, buf, n);
}
//关闭监听文件描述符和通信文件描述符
close(lfd);
close(cfd);
return 0;
}
客户端的开发
//客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{
//创建socket---用于和服务端进行通信
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if(cfd<0)
{
perror("socket error");
return -1;
}
//连接服务端
//int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
struct sockaddr_in serv;
serv.sin_family = AF_INET;
serv.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
printf("[%x]\n", serv.sin_addr.s_addr);
int ret = connect(cfd, (struct sockaddr *)&serv, sizeof(serv));
if(ret<0)
{
perror("connect error");
return -1;
}
int n = 0;
char buf[256];
while(1)
{
//读标准输入数据
memset(buf, 0x00, sizeof(buf));
n = read(STDIN_FILENO, buf, sizeof(buf));
//发送数据
write(cfd, buf, n);
//读服务端发来的数据
memset(buf, 0x00, sizeof(buf));
n = read(cfd, buf, sizeof(buf));
if(n<=0)
{
printf("read error or server closed, n==[%d]\n", n);
break;
}
printf("n==[%d], buf==[%s]\n", n, buf);
}
//关闭套接字cfd
close(cfd);
return 0;
}
最后留下一个过程图