网络编程基础

网络基础

协议的概念

什么是协议
协议就是规则,是数据传输和数组的解释的规则

两个之间传输信息必须要进过三次
第一次,传输文件名,接收方接收到文件名,应答OK给传输方;(知道要传什么)
第二次,发送文件的尺寸,接收方接收到该数据再次应答一个OK;(接受到了)
第三次,传输文件内容。同样,接收方接收数据完成后应答OK表示文件内容接收成功。(接受到了)

网络应用程序设计模式

C/S模式
传统的网络应用设计模式,客户机(client)/服务器(server)模式。需要在通讯两端各种部署客户机和服务器来完成数据通信

B/S模式

浏览器()/服务器(server)模式。只需在一端部署服务器,而另外一端使用各台pc都默认配置的浏览器即可完成数据的传输

分层模型
在这里插入图片描述
在这里插入图片描述
数据打包传输

要传输一个数据给另一台电脑,将我们的数据开始封装,传达到另一台电脑就会一层一层解除封装,显示我我们原本的信息

支持我们设定的网络协议就会使用什么特定的api读取,不然无法读取

在这里插入图片描述
在这里插入图片描述
数据开始通过网卡传输,然后通过一系列设备才到网络环境中


通信过程
在这里插入图片描述
封装好的数据为什么可以传递到我们想要的地方

路由寻址(利用ip和以太网帧)

一个路由器叫做一个路由节点,里面存放了一个表格,表格里面是这个路由可以到达的下一个路由的ip地址,我们最初的数据里面存放了目的地的ip地址,就这样一点点接近我们的目的地ip
在这里插入图片描述

TCP协议稳定,一次传输成功就会记住这个路线

以太网帧格式
在这里插入图片描述
目的地址
数据包下一个前往的网卡的硬件地址(网卡编号)
源地址
自己的硬件地址

根据类型这个几个数据来控制是传请求还是传数据

APR请求下一个进往的路由器的硬件地址

以太寻路
在这里插入图片描述
每一次进过路由器都要解包,更新数据打包
在这里插入图片描述
TTL;数据包传输的最长生命周期

ip段格式(对应以太网帧的数据)
在这里插入图片描述

传输层协议
1、UDP
每一个应用都有一个端口号(进程),这样消息就可以在我们指定的qq上传输
在这里插入图片描述
TCP数据报格式
在这里插入图片描述
NAT映射

数据先发送到交换机,然后交换机发送到路由器
NAT映射表
将私有ip转换成公网ip

一个路由器只有一个公网ip,但是我们一个路由器可以连接多个电脑,这些电脑的ip就是私有的,192.168这就是私有ip,要在网络中传输要转换成公网ip

打洞

在qq上传输信息,要经过腾讯的服务器
在这里插入图片描述
路由器会屏蔽陌生ip,但是我们两个都登入了腾讯的服务器,这样腾讯服务器对双方而言就不是陌生ip了
腾讯服务器给他们两个打洞,高效连接
在这里插入图片描述

socket套接字(插座)
成对出现,在内核中一个文件描述符对应两个缓冲区
在这里插入图片描述

ip地址:网络中辨识一个主机
端口号:在电脑中辨识一个进程
Ip + 端口 = 网络环境中唯一辨识一个进程(socket)

网络字节序
大端
地地址存高位

小端
低地址存低位
在这里插入图片描述
一般本机采用小端存储,网络数据流采用大端字节序,为此我们调用以下库函数做网络字节序和主机字节序的转换

直接的在点分十进制与网络字节序直接转换
在这里插入图片描述
socket

sockaddr j结构体用来描述IPV4协议

Socket 简单来说是ip地址与端口的结合协议
1、一种地址与端口的结合描述协议
2、Tcp/IP协议的相关API的总称:网络API的集合实现
3、涵盖了stream socket/Datagram Socket

socket 的组成与作用:

          在网络传输中用于唯一标识两个端点的链接。

          端点:包括(ip+port)

          4个要素:客户端的地址、客户端的端口、服务器的地址、服务器端口。

Socke的传输原理

在这里插入图片描述

socket函数
创建一个套接字的结构体

bind函数

让socket结构体可以访问到我们本机的IP地址

将socket连接到我们主机的ip地址,这些主机所有的网卡都可使用socket

listen函数
规定可链接数量,与服务器要链接的客户端是多少个;

accept函数
开启链接口,等待客户端的链接;

这个会返回一个客户端的socket

connect函数
输入服务端的IP地址及服务端口,如果连接出错,返回socket.error错误;

项目各部分说明
TCP服务端
1、调用socket() 创建出一个套接子结构体
2、调用bind函数,使得socket结构体可以访问到本机ip和端口号
3、调用listen函数,设置同时可以与本机连接的客户端数量
4、调用accept函数,要是用户没有发起连接就是堵塞,要是发起了连接机会返回一个与客户端产生连接的套接字结构体
5、调用read函数读取
6、调用write函数将小写转换成大写,然后回写到accept那个结构体中

TCP客户端
1、调用socket创建一个套接字结构体
2、没有调用bind函数,会自动分配一个ip和端口号
3、调用connect,连接带服务器ip和端口号
在这里插入图片描述

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<ctype.h>
#include<arpa/inet.h>

#define SERV_IP "127.0.0.1"//本机ip
#define SERV_PORT 6666 //端口号


int main(void)
{
	int lfd;// 文件描述符

	int cfd;//与客户的产生关系的socket套接字

	
	struct sockaddr_in serv_addr;//创建一个绑定的端口和具体地址,服务端
       
       	struct sockaddr_in clie_addr;//创建一个绑定的端口和具体地址,客户端

        socklen_t clie_addr_len;//描述长度

	char buf[BUFSIZ];//BUF是表示空间的大小

	int n;//表示实际读到的字符

	//创建一个socket

        lfd =  socket(AF_INET,SOCK_STREAM,0);//地址类型,套接字类型,协议类型为自动
	                                     // 要是成功就会返回可以用的socket变量失败就返回错误代码
            	
	
	
	serv_addr.sin_family = AF_INET;//初始化地址协议类型 
        serv_addr.sin_addr.s_addr =htonl(INADDR_ANY);//初始化IP地址
        serv_addr.sin_port = htons(SERV_PORT);//初始化端口号



 
	//给socket绑定端口号与地址

	bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//socket函数返回的描述符、指定想要绑定的IP和端口、serv_addr的长度

 

       listen(lfd,128);//用于表述一个已捆绑未连接套接口的描述字、等待连接队列的最大长度
	      //成功返回0,失败返回-1
       

       clie_addr_len = sizeof(clie_addr);//下面的长度
       // 在服务器端上创建一个新的socket,将客户端的信息和新的socket绑定在一个,一次只能创建一个
       cfd =accept(lfd,(struct sockaddr *)&clie_addr,&clie_addr_len);//服务器的socket、客户端端口地址信息结构体、返回参数2的数据类型大小


    


      

      
      // 将读取到的小写转成大写
     while(1)
	      
    {
        n = read(cfd,buf,sizeof(buf));//接收端的socket、客户端消息的存储空间、存储空间的大小、数据读取方式
        
        for ( int i = 0; i < n; i++)
           
        {
          buf[i] = toupper(buf[i]);
        
        }

      //写给客户端
      
       write(cfd,buf,n);//从buf中写n个给客户端

    }      //关闭

      close(lfd);
      close(cfd);


      

  return 0;


}


#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#define SERV_IP "127.0.0.1"//本机ip
#define SERV_PORT 6666 //端口号

int main()
{

  int cfd;// 文件描述符

  int n ;

   char buf[BUFSIZ];


  cfd =  socket(AF_INET,SOCK_STREAM,0);//地址类型,套接字类型,协议类型为自动
                                       // 要是成功就会返回可以用的socket变量失败就返回错误代码
  
 

  struct sockaddr_in serv_addr;//创建一个结构体,绑定的端口和具体地址,服务端


  serv_addr.sin_family = AF_INET;//初始化地址协议类型
  serv_addr.sin_addr.s_addr =htonl(INADDR_ANY);//初始化IP地址
  serv_addr.sin_port = htons(SERV_PORT);//初始化端口号

  socklen_t serv_addr_len;//定义一个长度

  
  
  connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));   //标识一个未连接的socket,存放连接成功的socket对象、指向要连接套接字的sockaddr结构体的指针、sockaddr结构体的字节长度 



                   
 while(1)
    {

       fgets(buf,sizeof(buf),stdin);//从键盘获取数据

  
       write(cfd,buf,strlen(buf));//服务端去写
  
 
        n = read(cfd,buf,sizeof(buf));//读到n个数据
   

       write(STDOUT_FILENO,buf,n);//写到屏幕上

    }
   //关闭

   close(cfd);

   return 0;

} 

错误处理函数
上面的函数都会在被调用之后,返回一个值,我们可以根据这个返回值来判断函数的运行情况。为了简单程序
我们在另一个warp.c文件中对每一个返回值都创建一个专门的函数去观察,我们只需要在观察函数中调用我们的socket函数,就可以得到返回值,然后判断是否错误

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值