[网络]——浅析网络套接字

套接字

套接字概念

TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这种端点就叫做套接字(socket)或插口

这里出现了几个陌生的概念,第一个是Tcp,Tcp是一种网络传输层的协议,我们暂且不谈Tcp协议是啥,本篇博客我们其实还是围绕函数接口来进行讲解。第二个是ip地址,相信大家对于ip地址并不陌生,你可能具体不知道他是做什么的,但是你只要知道他是标识网络中的主机的。第三个是端口号的概念,对于本节内容,我们有必要为大家阐述什么是端口号。

端口号实际上是我们上面提到的Tcp协议中的一部分,后面的博客给大家讲解。端口号主要有以下的特点:

  • 端口号是一个2字节16位的整数
  • 端口号用来标识一个进程,告诉操作系统,当前这个数据要交给哪一个进程来处理
  • ip加端口号能标识我们网络中某个主机上的唯一一个进程,ip加端口号也就构成了套接字的概念
  • 一个端口号只能被一个进程所占用

看了上面的概念之后我们其实可以明白,端口号其实就是一个标志,它可以标志某个主机上的一个进程。但是有的同学疑惑就来了,那我们之前不是有一个进程id的概念么,他们之间有什么区别呢?举一个例子,你是某野鸡大学的学生,你大一开学时学校给了你011的学号,但是这一年你不学无数,好吃懒做,从不上课被退学了,然后经过一年"努力",你居然又上了这所大学,这次学校分配给你了一个012的学号,但是你的身份证在你的一身中从不会被改变。端口号也是同样的道理,一个进程可以有多个端口号,但是他只能有一个进程id。

简单认识TCP and UDP协议

TCP协议:

  • 传输层协议
  • 面向链接
  • 可靠传输
  • 面向字节流

UDP协议:

  • 传输层协议
  • 无链接
  • 不可靠传输
  • 面向数据报

上面tcp和udp的简单介绍中,你其实什么也不用关心,但是你必须要知道Tcp面向链接,Udp无链接。什么是链接呢?通俗一点来说就是你找了一个男(女)朋友,你脑海中本来有一个描述男朋友的结构体,然后你把你现在男朋友的信息填充进去,不管你男朋友走到哪里你都知道他是你对象,这其实就是链接。协议中Udp则不进行这种描述,反之Tcp需要进行建立连接,也就是为通信的双方构建描述双方信息的结构体。

套接字编程铺垫

那说了这么多套接字编程到底是干什么的,很多小白读者还是一头雾水。其实我们的套接字编程是为了让两个不同的网络主机可以实现通信,但是如果你仔细体会其中的道理我们会发现,我们需要通过端口号来标识进程,其实本质上是不同的俩个主机之间的进程在进行通信,所以归根结低,网络套接字编程从某种角度上说其实是进程间的通信

网络字节序

清楚了套接字编程是为了通信后,我们再谈另一个问题,我们前面在讲进程间通信时是一台主机上的俩个或者多个进程进行通信。通信就是为了收发数据,但是这里有一个棘手的问题,你应该还记得什么是主机大小端吧,如果你忘记了什么是大小端,那么戳笔者之前的博客链接主机的大小端
既然我们每一个主机都有自己的大小端,那么如果从一个小端机器向大段机器发送数据那么必然会出现不可预测的结果。不过如果你直发字符串就没有问题,因为字符是一个字节么,不管怎么读取都不会出现问题。
那么如何解决这些问题呢?与其从我们接收方俩端进行数据格式的重复转换,不如我们直接定义一个网络传输字符的规定,以后大家都用统一的大小端模式进行首发数据不就行了,所以这里就出现了我们的网络字节序的概念。Tcp/Ip协议通一规定网络数据流采用大端字节序,也就是低地址高字节。

  • 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存
  • 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主字节序的转换。这些函数名你囐一看感觉很很恶心,但是其实他们很好记住,h表示host,n表示network,l表示32位长整数,s表示16位短整数。
在这里插入图片描述
ps:笔者有时候看Linux的系统调用能给读者看吐了,但是谁让人家是系统调用呢,毕竟是底层的东西,越底层速度越快。这也就是有时候老铁们常调侃java的运行速度比c++慢的原因。java之所以好用就是封装的到位,但是速度相对来说会慢,c++速度快但是还在用指针这些底层难用的东西,不过笔者还是要小声bb一句。。。c++ forever(破音)。

socket编程接口详解

到这里,我们算是到了本博客的核心部分了,之前我们说了网络套接字编程进行主机之间的通信实际上也是进程间的通信,很多通学这里还是不太理解,那么我们先介绍一个函数,通过对这个函数的介绍我们再一次深入的理解socket编程本质。

创建socket对象函数

话不多,先把函数头给大佬们抬上来:图有点小,点开看大图
在这里插入图片描述
参数什么的先丢一边,睁开眼睛同学们,看看这个函数返回了什么。没错,他居然返回了一个文件描述符,你一定还记得匿名管道怎么通信的吧,匿名管道通过调用函数返回读写文件描述符,其实相当于写端将数据写到文件中,读端从这个文件中读出数据。而socket对象创建函数惊人的相似,他们的通信原理基本相同(只是原理相同),到这里你也就明白为什么我们要说主机通信其实是进程间通信。

  • socket是实现网络通信主机进程间通信的一种机制。从用户空间来看,socket就是一个文件描述符,对socket的操作等同于对普通文件的文件描述符进行操作,也就是说我们可以使用read,write,close等函数进行操作。一旦双方对该socket都进行初始化后,对端的数据交互都是通过该socket实现的。
  • 而从内核空间来看,socket不在简单的指向一个磁盘文件,相应的读写指针指向的代码亦是网卡驱动程序提供的数据发送或者数据接收函数。其主要资源是一个内核内存空间的struct sk_buff结构体对象。该结构体中描述了双方的基本信息,缓冲数据等。

现在你一定对网络通信编程有了更深一步的理解,到此时我们所有的铺垫全部做完,现在开始介绍网络编程的接口,我们本次讲解使用的是基于BSD的通信编程接口,这些接口隔离了下层的实现,只需要调用相应的接口就可以。
此时我们在做最后一步的铺垫,我们使用生活的一个例子来为大家进行讲解socket网络编程,因为系统调用还是过于生涩,不好理解,使用栗子能帮助我们更好的理解这些接口。

大家在生活中拨打电话应该是一个很常见的情景,那么我们用拨打方和接收方作为栗子来描述一下场景:

在这里插入图片描述
现在我们使用上面接听者拨打者栗子来给大家讲解我们套接字编程中的一些列接口。

在这里插入图片描述
在Linux操作系统中,要实现socket通信,通信双方都需要建立各自的socket对象,也就是本函数的返回值。当我们此函数调用成功之后,该socket对象没有绑定任何的端口号和ip信息,用我们上面的拨打电话的栗子来说,调用函数就相当于买了一台电话机,但是此时我们还没有绑定电话号码,所以还不能通信。

  • 参数1:参数一填写的是socket对象所以使用的地址簇,也就是此对象使用的协议类型,这里我们经常使用的有AF_INET表示是ipv4协议簇,PF_INET6表示ipv6的协议簇,PF_LOCAL表示本地通信。我们只要记住这三个即可,其余笔者查阅资料大多数文档中表示其他协议簇在Linux中目前还没有实现。
  • 参数2:第二个参数表示socket的类型,也就是要填写的套接字类型,这里就列举我们最长使用的三种:为流套接字类型SOCK_STREAM、数据报套接字类型为SOCK_DGRAM、原始套接字SOCK_RAW。从名字对比我们上面的Tcp/Udp简单介绍我们就知道Tcp使用流式套接字,Udp使用数据报套接字。
  • 参数3:第三个参数具体让你选择协议簇中的一种协议,这里大多数情况我们设置为0,让系统自己选择默认协议,但是原始套接字需要指定具体的协议

此时我们套接字对象就创建完了,我们现在相当于买了一台电话机,但是电话机还没有电话号码,所以下一步我们就需要做一些信息绑定工作。

绑定本地ip和端口

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值