网络编程用到的函数

记录一些《Linux高性能服务器》中用到的函数。

先说说什么是API。操作系统是软硬件的交界面,百度百科说:

API(Application Programming Interface,应用程序接口)是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。 用来提供应用程序与开发人员基于某软件或硬件得以访问的一组例程,而又无需访问源码,或理解内部工作机制的细节。

操作系统是用户与计算机硬件系统之间的接口,用户通过操作系统的帮助,可以快速、有效和安全、可靠地操纵计算机系统中的各类资源,以处理自己的程序。为使用户能方便地使用操作系统,OS 又向用户提供了如下两类接口

(1) 用户接口:操作系统专门为用户提供了“用户与操作系统的接口” ,通常称为用户接口。该接口支持用户与 OS 之间进行交互,即由用户向 OS 请求提供特定的服务,而系统则把服务的结果返回给用户。

(2) 程序接口:操作系统向编程人员提供了“程序与操作系统的接口” ,简称程序接口,又称应用程序接口 API(Application Programming Interface)。 该接口是为程序员在编程时使用的,系统和应用程序通过这个接口,可在执行中访问系统中的资源和取得 OS 的服务,它也是程序能取得操作系统服务的唯一途径。大多数操作系统的程序接口是由一组系统调用(system call)组成,每一个系统调用都是一个能完成特定功能的子程序  。

应用程序接口又称为应用编程接口,是一组定义、程序及协议的集合,通过 API接口实现计算机软件之间的相互通信。API 的一个主要功能是提供通用功能集。API同时也是一种中间件,为各种不同平台提供数据共享。程序设计的实践中,编程接口的设计首先要使软件系统的职责得到合理划分。良好的接口设计可以降低系统各部分的相互依赖,提高组成单元的内聚性,降低组成单元间的耦合程度,从而提高系统的可维护性和可扩展性。

所以下面介绍的这些函数,其实都是操作系统提供给程序员的程序接口,就是一组系统调用(例如socket,listen,accept这些函数),利用这些函数可以让操作系统帮助我们做事。操作系统内核不能让我们随意操作,所以必须由操作系统来控制资源的使用。

第5章 Linux网络编程基础API

socket地址API  

一个IP地址和一个端口号组成的 (ip, port) 唯一表示了使用TCP通信的一端,称作socket地址。

1.主机字节序和网络字节序

小端字节序也叫主机字节序,PC多用这个。是指整数的高位字节存储在内存高地址处,而低位字节则存储在内存的低地址处。

大端字节序也叫网络字节序,网络传输都用这个。是指将整数的高位字节存储在内存的低地址处,低位字节存储在内存的高地址处。32位机的CPU的累加器一次能装载至少4字节——32bit,表示一个整数,则高位字节23~31bit存储在低地址处,而低位字节0~7bit存储在高地址处。

为了收发双方使用的字节序避免不一致导致解释错误,发送端总是把要发的数据转为大端字节序再发送,而接收端知道对方传来的数据是大端字节序,所以根据自身采用的字节序觉得是否转换。大端字节序为所有接收数据的主机提供了一个正确解释收到的格式化数据的保证。

可以用代码检查机器大小端。两种字节序之间可转换:

  •  htonl 和htons:主机字节序转网络字节序
  •  ntohl和ntohs:网络字节序转主机字节序

这里的l代表long 长整型,s代表short 短整型。

2.通用socket地址——sockaddr

 sa_family成员是地址族类型(sa_family_t)的变量,地址族类型通常和协议族类型对应。

协议族protocal,也叫domain。

 表格里这些PF_*和AF_*是宏,二者有完全相同的值,它们定义在<bits/socket.h>。

 sa_data成员存放socket地址值,但是不同协议族的地址值具有不同的含义和长度。但data只有14字节(Byte)可能放不下下面这些协议所需要的108B、26B等等。

 所以又来一个通用socket地址结构体,提供了足够的空间,且是内存对齐的:

 

 3.专用socket地址——sockaddr_**

上面两个通用socket地址结构体不太好用,比如设置和获取IP地址和端口号就需执行繁琐的位操作。所以Linux为各个协议族提供了专门的socket地址结构体,前面说过有3个协议族。

  • PF_UNIX(AF_UNIX) UNIX本地域协议族: struct sockaddr_un
  • PF_INET(AF_INET)  TCP/IPv4协议族:     struct sockaddr_in,其中IP地址由struct in_addr定义
  • PF_INET6(AF_INET6) TCP/IPv6协议族:  struct sockaddr_in6,其中IPv6地址由struct in6_addr定义

 

 所有专用socket地址以及sockaddr_storage类型的变量实际使用时都需要转化为通用socket地址类型sockaddr(强制转换即可),因为所有socket编程接口使用的地址参数的类型都是sockaddr。

 4.IP地址转换函数

人习惯用可读性好的点分十进制字符串来表示IP地址,用十六进制字符串表示IPv6地址,但编程需要转为整数(二进制数)。

 不可重入是指静态变量上次存储的内容,再次调用inet_ntoa函数后被覆盖了。

 还有3个函数也和inet_addr、inet_aton、inet_ntoa有同样功能,同时可用于IPv4和IPv6地址:

socket基础API   <sys/socket.h>

创建socket(socket),命名socket(bind),监听socket(listen),接受连接(accept),发起连接(connect),读取数据,获取地址信息,检测带外标记,以及读取和设置socket选项。

1.创建socket——socket

  • domain参数是协议族
  • type参数指定服务类型,SOCK_STREAM(流服务)和SOCK_UGRAM(数据报服务)。对TCP/IP协议族而言,流服务表示传输层用TCP,数据报服务表示传输层用UDP。
  • protocal参数是在前两个参数构成的协议集合下再选一个具体协议,这个值通常是由前两个参数唯一确定的。所以把它设置为0表示使用默认协议。
  • socket系统调用成功时返回一个socket文件描述符,失败返回-1并这是errno

 2.命名socket——bind

创建socket时只给它指定了地址族,但没指定使用该地址族中哪个具体socket地址。将一个socket与socket地址绑定称为给socket命名,其实就是绑定bind。

在服务器程序中,通常要命名socket,因为只有命名后客户端才能直到该如何连接它。

客户端通常不需要命名socket,而是采用匿名方式,即使用操作系统自动分配的socket地址。

 3.监听socket——listen

socket被命名后还不能马上接受客户连接,还需创建一个监听队列以存放待处理的客户连接。

 4.接受连接——accept

服务器通过读写这个返回的新socket来和被连接的客户端通信,而负责监听的那个socket会继续监听新的连接请求。当监听队列里处于ESTABLISHED状态的连接对应的客户端出现网络异常或者提取退出,服务器对这样一个连接执行accept调用会怎样?会正常返回。

5. 发起连接——connect

服务器通过listen调用来被动接受连接,那么客户端需通过accept系统调用来请求与服务器建立连接。

 注意,客户端在请求连接connect之前,也需要先调用socket函数创建socket,但不需要bind。因为客户端通常不需要命名socket,而是采用匿名方式,即使用操作系统自动分配的socket地址。

 6.关闭连接——close,shutdown

关闭连接实际上就是关闭该连接对应的socket,可以用关闭普通文件描述符的系统调用来完成。

 注意:父进程和子进程都需要关闭一次这个socket才行!

如果想立即终止连接而不是将socket的引用计数减1,可以用shutdown系统调用,它是专门为网络编程设计的。

 7.数据读写

(1)TCP数据读写——recv,send

flags是一些额外控制,例如是否阻塞、是否紧急。

 MSG_OOB表示发送和接收带外数据。

(2) UDP数据读写——recvform,sendto

 (3)通用数据读写函数——recvmsg,sendmsg

 (4)带外标记——sockatmark

socket网络信息API   <netdb.h>

实现主机名和IP地址之间的转换,以及服务器名称和端口号之间的转换。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值