IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> TCP/IP网络编程 -> 正文阅读

[网络协议]TCP/IP网络编程

基于Linux的套接字相关函数

在 linux 下,socket 也被认为是文件的一种。

文件的读写:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcnt1.h>

int open(const char* path, int flag);
#include <unistd.h>

ssize_t write(int fd, const void* buf, size_t nbytes);

int close(int fd);
#include <unistd.h>
ssize_t read(int fd, void* buf, size_t nbytes);

open 函数的返回值即文件描述符,也即 close 函数的参数。

ps: size_t 是通过 typedef 声明的 unsigned int 类型;ssize_t 是通过 typedef 声明的 signed int 类型。

  1. 服务端套接字创建过程
#include <sys/socket.h>
#include <unistd.h>

// 创建 socket
int socket(int domaink, int type, int protocol);
// 绑定ip,端口号
int bind(int sockfd, struct sockaddr* myaddr, socklen_t addrlen);
// 创建监听
int listen(int sockfd, int backlog);
// 接受连接
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
// 发送数据
ssize_t write(int fd, const void* buf, size_t nbytes);
// 关闭套接字
int close(int fd);
  1. 客户端套接字创建过程
#include <sys/socket.h>
#include <unistd.h>

// 创建 socket
int socket(int domaink, int type, int protocol);
// 请求连接
int connect(int sockfd, struct sockaddr* serv_addr, socklen_t addrlen);
// 接收数据
ssize_t read(int fd, void* buf, size_t nbytes);
// 关闭套接字
int close(int fd);

基于Windows的套接字相关函数

#include <WinSock2.h>

// 初始化,可借助 MAKEWORD(1, 2);函数构建WORD型版本信息
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

Windows 严格区分文件 I/O 函数和套接字 I/O 函数。

#include <WinSock2.h>

int send(SOCKET s, const char* buf, int len, int flags);

int recv(SOCKET s, const char* buf, int len, int flags);
  1. 服务端套接字创建过程
#include <WinSock2.h>
// 初始化
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
// 创建套接字
SOCKET socket(int af, int type, int protocol);
// 绑定ip,端口号
int bind(SOCKET s, const struct sockaddr* name, int namelen);
// 创建监听
int listen(SCOKET s, int backlog);
// 接受连接
SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen);
// 发送数据
int send(SOCKET s, const char* buf, int len, int flags);
// 关闭套接字
int closesocket(SOCKET s);
// 注销初始化
int WSACleanup(void);
  1. 客户端套接字创建过程
#include <WinSock2.h>
// 初始化
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
// 创建套接字
SOCKET socket(int af, int type, int protocol);
// 请求连接
int connect(SOCKET s, const char* buf, int len, int flags);
// 接收数据
int recv(SOCKET s, const char* buf, int len, int flags);
// 关闭套接字
int closesocket(SOCKET s);
// 注销初始化
int WSACleanup(void);

套接字类型及协议

int socket(int domaink, int type, int protocol);

domain

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

type

面向连接的套接字 SOCK_STREAM,特点:可靠传输,有序传输,不存在数据边界

面向消息的套接字 SOCK_DGRAM,特点:快速船务,无序传输,有数据边界,限制传输数据大小

protocol

满足 PF_INET + SOCK_STREAM 的只有 IPPROTO_TCP
满足 PF_INET + SOCK_DGRAM 的只有 IPPROTO_UDP

地址族与数据序列

int bind(int sockfd, struct sockaddr* myaddr, socklen_t addrlen);

struct sockaddr_in

struct sockaddr_in
{
  sa_family_t sin_family; // 地址族
  uint16_t sin_port;      // 16位 TCP/UDP 端口号
  struct in_addr;         // 32位 IP 地址
  char sin_zero[8];       // 不使用
}

struct in_addr
{
  In_addr_t s_addr;   //32位 IP 地址
}

sockaddr_in 成员分析

sin_family

sin_port
保存16位端口号,重点在于,它以网络字节序保存.

sin_addr
该成员保存32位IP地址信息,且也以网络字节序保存。

sin_zero
只为使 sockaddr_in 的大小与 sockaddr 结构体保持一致而插入的成员,必须填充为0。

使用举例:

struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(argv[1]));

int bind(serv_sock, (struct sockaddr*) serv_addr, sizeof(serv_addr));

网络字节序与地址变换

在通过网络传输数据时约定统一方式,这种约定称为网络字节序,统一为大端序。

字节序转换函数:

unsigned short htons(unsigned short);
unsigned short ntols(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);

h 代表 host, n 代表 network, s 代表 short, l 代表 long

那么 htons 即“把short型数据从网络字节序转化为主机字节序”

网络地址的初始化与分配

将点分十进制格式的字符串转为32位整型数据的函数

#include <arpa/inet.h>

in_addr_t inet_addr(const char* string);

与之类似的函数

#include <arpa/inet.h>

int inet_aton(const char* string, struct in_addr* addr);

成功时返回1,失败返回0;string 含有需要转换IP地址信息的字符串地址,将保存转换结果的 in_addr 结构体变量的地址值。

请查看该函数的源码,了解一下是怎么转换的。

介绍一个相反的函数,将32位整型数据转化为点分十进制的IP字符串形式

#include <arpa/inet.h>

char * inet_ntoa(struct in_addr adr);

失败时返回-1

网络地址初始化:

结合前面所述,套接字创建过程中常见的网络地址信息初始化方法如下:

struct sockaddr_in addr;
char* serv_ip = "211.217.168.13";
char* serv_port = "9190";
memset(&addr, 0, sizeof(addr));   // 结构体变量 addr 的所有成员初始化为0
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(serv_ip);
addr.sin_port = htons(atoi(serv_port));   // atoi 函数,将字符串类型的值转为整数型

而采用 INADDR_ANY 的方式,则可自动获取运行服务器端的计算机 IP 地址。

addr.sin_addr.s_addr = htonl(INADDR_ANY);

(未完待续)

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-07-31 16:59:17  更:2021-07-31 17:00:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:45:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码