Linux——网络编程套接字

Posted _BitterSweet

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux——网络编程套接字相关的知识,希望对你有一定的参考价值。

1.预备知识储备

1.1源IP地址和目的地址

  • 在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址
  • 源IP地址表示从哪来,目的IP地址表示到哪去

1.2端口号

  • 端口号是传输层协议的内容
  • 端口号是一个2字节16位的整数
  • 端口号用来标识一个进程,并告诉操作系统,把当前这个进程去交给谁处理
  • IP地址 + 端口号能够标识某一台主机的某一个进程
  • 一个端口号只能被一个进程占用

1.2.1端口号与进程id的联系

  • 进程中,pid可以表示一个进程,那么端口号也是唯一标识一个进程
  • 进程不一定有端口号,只有在网络中的进程才会被分配端口号
  • 一个端口号只能绑定一个进程,但是一个进程可以绑定多个端口号

1.3套接字

  • IP地址 + 端口号 就等于套接字,可以标识全网唯一的进程,即形成了进程间通信
  • IP地址可以保证主机的唯一性
  • 端口号可以保证进程的唯一性
  • 同一主机下的进程间通信:文件是公共资源
  • 在网络间的进程通信:网络是公共资源

1.4源端口号和目的端口号

  • 传输层协议(TCP和UDP)的数据段中有两个端口号, 分别叫做源端口号目的端口号就是在描述 “数据是谁发的, 要发给谁”

2.认识TCP/UDP协议

2.1 TCP协议特点

  • 传输层协议
  • 有链接
  • 可靠传输
  • 面向字节流(没有数据边界,接收方无法判别连续传输的数据,可以一次接受,也可以分多次接受)

2.2 UDP协议特点

  • 传输层协议
  • 无连接(在通信前,不需要发送链接请求)
  • 不可靠传输
  • 面向数据报

3.网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

3.1主机字节序

  • 字节序:CPU对内存的访问顺序
  • 小端字节序:低位放低地址
  • 大端字节序:高位放高地址
  • 什么是主机字节序:指的是机器本身的字节序,如果是大端,则主机字节序就是大端;如果是小端,主机字节序就是小端

3.2网络字节序(规定网络中传输的字节序使用大端)

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

3.3网络字节序和主机字节序间的相互转换接口

  • 为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换

3.3.1主机字节序转网络字节序

在这里插入图片描述

3.3.2网络字节序转主机字节序

在这里插入图片描述

4.Socket编程接口

4.1socket常见API

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);

// 绑定端口号 (TCP/UDP, 服务器) 
int bind(int socket, const struct sockaddr *address,
 socklen_t address_len);

// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);

// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,
 socklen_t* address_len);

// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
 socklen_t addrlen);

4.2sockaddr结构

  • socket API是一层抽象的网络编程接口,适用于各种底层网络协议,比入IPv4,IPv6,但是各种网络协议的地址格式并不相同
    在这里插入图片描述
  • IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址
  • IPv4IPv6地址类型分别定义为常数AF_INETAF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容
  • socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数
  • 设计成这样的结构体就可以一套接口实现多种通信(类似C++中的多态)
  • sockaddr内部结构
  • 执行该命令,即可查看
vim /usr/include/linux/in.h

在这里插入图片描述

以上是关于Linux——网络编程套接字的主要内容,如果未能解决你的问题,请参考以下文章

套接字编程中的Java拖放问题

linux 套接字编程入门--Hello World

linux 网络套接字

linux下的UDP套接字编程

linux 中 C++ 中的 UDP Socket 编程

MultiSocket 监听 Linux 套接字编程