linux程序设计(套接字)+TCP/IP网络编程学习笔记

linux程序设计(套接字)+TCP/IP网络编程学习笔记


什么是套接字?

应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口,区分不同应用程序进程间的网络通信和连接。

网络化的应用程序在开始任何通讯之前都必需要创建套接字。就像电话的插口一样,没有它就完全没办法通信。

生成套接字,主要有3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号。

Socket可以看成在两个程序进行通讯连接中的一个端点,一个程序将一段信息写入Socket中,该Socket将这段信息发送给另外一个Socket中,使这段信息能传送到其他程序中.

这里写图片描述

Host A上的程序A将一段信息写入Socket中,Socket的内容被Host A的网络管理软件访问,并将这段信息通过Host A的网络接口卡发送到Host B,Host B的网络接口卡接收到这段信息后,传送给Host B的网络管理软件,网络管理软件将这段信息保存在Host B的Socket中,然后程序B才能在Socket中阅读这段信息。

通过套接字接口可以实现网络间的进程通信.

端口号就是在同一操作系统内为区分不同套接字而设置的,因此无法将1个端口号分配给不同的套接字.虽然端口号不能重复,但TCP套接字和UDP套接字不会公用端口号,所以允许重复.

套接字是一种通信机制,这使得客户/服务器系统的开发工作即可以在本地单机上进行,也可以跨网络进行.linux所提供的功能(如打印服务,连接数据库和提供web页面)和网络工具(如用于远程登录的rlogin和用于文件传输的ftp)通常都是通过套接字来进行通信的.
套接字明确的将客户和服务器区分开来,这与管道是有区别的.套接字机制可以实现将多个客户连接到一个服务器.

基于Linux的文件操作

对于Linux而言,socket操作与文件操作没有区别,socket被认为是文件的一种,因此在网络数据传输的过程中可以使用文件I/O的相关函数.

文件描述符是系统分配给文件或套接字的整数

分配给标准输入输出及标准错误的文件描述符:

文件描述符 对象
0 标准输入:Standard Input
1 标准输出:Standard Output
2 标准错误:Standard Error

1.打开文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path,int flag);
成功时返回文件描述符,失败返回-1
  • path 文件名的字符串地址
  • flag 文件打开模式信息(如需传递多个参数,则应通过位或运算(OR)符组合并传递)

文件打开模式:

打开模式 含义
O_CREAT 必要时创建文件
O_TRUNC 删除全部现有数据
O_APPEND 维持现有数据,保存到其后面
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读写打开

2.关闭文件

#include <unistd.h>
int close(int fd);
成功时返回0,失败返回-1
  • fd 需要关闭的文件或套接字的文件描述符

3. 将数据写入文件

write函数用于向文件输出(传输)数据.Linux系统中不区分文件与套接字,通过套接字向其他计算机传递数据时也用write函数

#include <unistd.h>
ssize_t wirte(int fd,const void *buf,size_t nbytes);
成功时返回写入的字节数,失败返回-1
  • fd 显示数据传输对象的文件描述符
  • buf 保存要传输数据的缓冲地址值
  • nbytes 要传输数据的字节数
    size_t是通过typedef声明的unsigned int类型.对ssize_t来说,size_t前面多加的s代表signed,即ssize_t是通过typedef声明的signed int类型

4.读取文件中的数据

#include <unistd.h>
ssize_t read(int fd,void *buf,size_t nbytes);
成功时返回接收的字节数(但遇到文件结尾则返回0),失败时返回-1
  • fd 显示数据接收对象的文件描述符
  • buf 要保存接收数据的缓冲地址值
  • nbytes 要接收数据的最大字节数

文件描述符与套接字

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>

int main()
{
  int fd1,fd2,fd3;
  fd1=socket(PF_INET,SOCK_STREAM,0);
  fd2=open("test.dat",O_CREAT|O_WRONLY|O_TRUNC);
  fd3=socket(PF_INET,SOCK_STREAM,0);

  printf("file descriptor 1: %d\n",fd1);
  printf("file descriptor 2: %d\n",fd2);
  printf("file descriptor 3: %d\n",fd3);

  close(fd1);
  close(fd2);
  close(fd3);

  return 0;
}

//从输出的文件描述符整数值可以看出,描述符从3开始以由大到小的顺序编号,因为0,1,2是分配给标准I/O的文件描述符

套接字连接

理解套接字应用程序如何通过套接字维持一个连接?
1. 服务器应用程序用系统调用socket来创建一个套接字,它是系统分配给该服务器进程的类似文件描述符的资源,它不能与其他进程共享.
2. 服务器进程给创建的套接字分配一个名字.本地套接字的名字是linux文件系统中的文件名,一般放在/tmp或/usr/tmp目录中.网络套接字的名字是与客户连接的特定网络有关的服务标识符(端口号或访问点).该标识符允许linux将进入的针对特定端口号的连接转到正确的服务器进程.

  • 系统调用bind给套接字命名,然后服务器进程就开始等待客户连接到这个命名套接字.
  • 系统调用listen创建一个用于存放来自客户的进入连接的队列
  • 服务器通过系统调用accept来接受客户的连接

3 服务器调用accept时,会创建一个与原有的命名套接字不同的新套接字.新建套接字只用于与这个特定的客户进行通信,而命名套接字被保留下来继续处理来自其他客户的连接.服务器可以同时接受多个连接.对于一个简单的服务器,后续的客户将在监听队列中等待,直到服务器再次准备就绪.
4. 基于套接字系统的客户端更加简单.客户首先调用socket创建一个未命名套接字,然后将服务器的命名套接字作为一个地址来调用connect与服务器建立连接.
5. 一旦连接建立,就可以像使用底层文件描述符那样用套接字来实现双向的数据通信.

套接字属性

3个属性决定套接字的特性:域(domain),类型(type),以及协议(protocol).套接字还用地址作为它的名字.地址的格式随域(又被称为协议族,protocol family)的不同而不同.每个协议族又可以使用一个或多个地址族来定义地址格式.(每种地址族适用的地址族均不同)

1. 套接字的域(域又称为协议族)

域指定套接字通信中使用的网络介质.最常见的套接字域是AF_INET,它指的是Internet网络.其底层的协议–网际协议(IP)只有一个地址族,它使用IP地址来指定网络中的计算机.

客户通过IP端口指定一台联网机器上的某个特定的服务.系统内部,使用一个唯一的16位整数来标识端口;系统外部,需要通过IP地址和端口号的组合来确定.套接字作为通信的终点,它必须在开始通信之前绑定一个端口.

服务器在特定的端口等待客户的连接.标准服务对应知名端口号(标准端口号).本地服务可以使用非标准的端口地址.

UNIX文件系统域AF_UNIX,一台位联网的计算机上的套接字也可以使用该域.这个域的底层协议就是文件输入/输出,而它的地址就是文件名.

头文件sys/socket.h中声明的协议族

名称 协议族
PF_INET IPv4互联网协议族
PF_INET6 IPv6互联网协议族
PF_LOCAL 本地通信的UNIX协议族
PF_PACKET 底层套接字的协议族
PF_IPX IPX Novell协议族

套接字中实际采用的最终协议信息是通过socket函数的第三个参数传递的.在指定的协议族范围内通过第一个参数决定第三个参数.

2. 套接字类型

套接字类型指的是套接字的数据传输方式,该类型决定了创建的套接字的数据传输方式.
一个套接字域可能有多种不同的通信方式,而每种通信方式又有其不同的特性.但AF_UNIX域的套接字提供了一个可靠的双向通信路径.

因特网协议提供了两种通信机制:流(stream)和数据包(datagram).

面向连接的套接字(SOCK_STREAM)

流套接字(在某些方面类似与标准的输入/输出流)提供的是一个有序,可靠,双向字节流的连接.因此发送的数据可以确保不会丢失,复制或乱序到达,并且在这一过程中发生的错误也不会显示出来.大的消息将被分片,传输,再重组.这很像一个文件流,它接收大量的数据,然后以小数据块的形式将它们写入底层磁盘.流套接字的行为是可预见的.

由类型SOCK_STREAM指定流套接字,它们是在AF_INET域中通过TCP/IP连接实现的.它们也是AF_UNIX域中常用的套接字类型.

TCP/IP代表的是传输控制协议(Transmission Control Protocol)/网际协议(Internet Protocol).IP协议是针对数据包的底层协议,它提供从一台计算机通过网络到达另一台计算机的路由.TCP协议提供排序,流控和重传,以确保大数据的传输可以完整的到达目的地或报告一个适当的错误条件.

SOCK_STREAM特征:

  • 传输过程中数据不会消失
  • 按序传输数据
  • 传输的数据不存在数据边界

收发数据的套接字内部有缓冲(buffer),即字节数组.通过套接字传输的数据将保存到该数组.因此,收数据并不意味着马上调用read函数,只要不超过数组容量,则有可能在数据填充满缓冲后通过1次read函数调用读取全部,也有可能分成多次read函数调用进行读取.

面向消息的套接字(SOCK_DGRAM)

由类型SOCK_DGRAM指定的数据报套接字不建立和维持一个连接.它对可以发送的数据报的长度有限制.数据报作为一个单独的网络消息被传输,它可能会丢失,复制或乱序到达.

数据报套接字是在AF_INET域中通过UDP/IP连接实现的,它提供的是一种无序的不可靠服务.优点:开销较小,速度快.

数据报适用于信息服务中的”单次”(single-shot)查询,它主要用来提供日常状态信息或执行低优先级的日志记录.它的优点是服务器的崩溃不会给客户端造成不便,也不会要求客户重启,因为基于数据报的服务器通常不保留连接信息,所以它们可以在不打扰其客户的前提下停止并重启.

SOCK_DGRAM特征:

  • 强调快速传输而非传输顺序
  • 传输的数据可能丢失也可能损毁
  • 传输的数据有数据边界
  • 限制每次传输的数据的大小
  • 存在数据边界(意味着接收数据的次数应和传输次数相同)

套接字协议

只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议.(UNIX网络套接字和文件系统套接字)
socket函数的前两个参数传递了协议族信息和套接字数据传输方式,大部分情况下可以向第三个参数传递0,除非遇到下面的情况:

同一协议族中存在多个数据传输方式相同的协议
数据传输方式相同,但协议不同,此时需要通过第三个参数具体指定协议信息.

  • IPPROTO_TCP “IPv4协议族中面向连接的套接字”
  • IPPROTO_UDP “IPv4协议族中面向消息的套接字”

TCP服务器端的默认函数调用顺序

  • socket()创建套接字
  • bind()分配套接字地址
  • listen()等待连接请求状态
  • accept()允许连接
  • read()/write()数据交换
  • close()断开连接
    这里写图片描述

TCP客户端的默认函数调用顺序

  • socket()创建套接字
  • connect()请求连接
  • read()/write()交换数据
  • close()断开连接
    这里写图片描述

基于TCP/IP的服务器端/客户端函数调用关系

这里写图片描述
整体流程如下:服务器端创建套接字后连续调用bind,listen函数进入等待状态,客户端通过调用connect函数发起连接请求.客户端只能等到服务器端调用listen函数后才能调connect函数.客户端调用connect函数前,服务器端可能先调用accept函数,此时服务器端在调用accept函数时进入阻塞状态,直到客户端调用connect函数为止.

创建套接字

socket系统调用创建一个套接字并返回一个描述符,该描述符可以用来访问该套接字.

#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain,int type,int protocol);
成功时返回文件描述符,失败时返回-1

创建的套接字是一条通信线路的一个端点.

  • domain指定协议族(套接字中使用的协议族信息)
  • type参数指定这个套接字的通信类型(套接字数据传输类型)
  • protocol参数指定使用的协议(计算机间通信中使用的协议信息)

每种协议族适用的地址族均不同,如IPv4使用4字节地址族,IPv6使用16字节地址族.

关于PF_INET和AF_INET的区别?

在写网络程序的时候,建立TCP socket:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值