怎样做自己的网站和发布网站,中国铁建商城电子商务平台,手机版网站如何制作软件,网站建设的1.Socket套接字编程
1.1.什么是socket套接字编程
Socket套接字编程 是一种基于网络层和传输层网络通信方式#xff0c;它允许不同主机上的应用程序之间进行双向的数据通信。Socket是网络通信的基本构件#xff0c;它提供了不同主机间的进程间通信端点的抽象。一个Socket就是…1.Socket套接字编程
1.1.什么是socket套接字编程
Socket套接字编程 是一种基于网络层和传输层网络通信方式它允许不同主机上的应用程序之间进行双向的数据通信。Socket是网络通信的基本构件它提供了不同主机间的进程间通信端点的抽象。一个Socket就是一个通信端点它提供了应用程序访问网络通信协议如TCP/IP的接口。并且Socket编程基于客户端Client和服务器端Server进行全双工通信 客户端通常指的是发起连接请求的一方它使用Socket API创建一个Socket对象并指定要连接的服务器地址和端口号然后向服务器发送连接请求。连接建立后客户端就可以通过Socket发送和接收数据了。服务器端则是监听来自客户端的连接请求的一方。服务器端也使用Socket API创建一个Socket对象并绑定到一个指定的地址和端口号上然后开始监听来自客户端的连接请求。当有客户端连接时服务器端会接受这个连接并创建一个新的Socket对象来与这个客户端进行通信。 简单来说Socket编程就是使用Socket API应用程序接口来编写网络应用程序。这些网络应用程序可以是客户端也可以是服务器端它们通过Socket进行数据的发送和接收。
1.2.如何进行socket套接字编程
首先socket套接字编程是基于TCP、IP四层网络协议栈实现的而在传输层协议中UDP协议是无连接、面向数据报的TCP协议是有链接、面向字节流的因此系统维护了两套Socket套接字编程接口给UDP场景和TCP场景使用
1.2.1.UDP的套接字编程
// UDP服务器
{int port; // 服务器开放的端口号int sock_fd socket(AF_INET, SOCK_DGRAM, 0); // 网络通信UDP套接字// 填充sockaddr结构体对象struct sockaddr_in local;bzero(local, sizeof(local)); // 初始化结构体local.sin_family AF_INET; // 绑定网络通信local.sin_port htons(); // 绑定端口local.sin_addr.s_addr INADDR_ANY; // 允许所有外来ip访问// 绑定指定网络信息和指定的文件系统int n ::bind(sock_fd, (struct sockaddr *)local, sizeof(local));// 获取客户端信息char buff_r[1024];sockaddr_in peer;socklen_t len sizeof(peer);ssize_t n recvfrom(sock_fd, buff_r, sizeof(buff_r) - 1, 0, (struct sockaddr *)peer, len);// 给客户端发送信息std::string buffer;ssize_t m sendto(sock_fd, buffer.c_str(), buffer.size(), 0, (struct sockaddr *)peer, len);
} 服务器进行套接字编程流程 通过socket函数获取套接字其中SOCK_DGRAM对应UDP协议构建一个sockaddr_in对象并绑定端口和设置允许任意的IP地址访问服务器接着通过bind函数显性绑定套接字和sockaddr_in对象接下来就可以和客户端进行IO通信了 / UDP客户端
{int port_server; // 链接服务器的端口号int ip_server; // 链接服务器的端口号int sock_fd socket(AF_INET, SOCK_DGRAM, 0); // 网络通信UDP套接字struct sockaddr_in server;bzero(server, sizeof(server)); // 初始化结构体server.sin_family AF_INET; // 设置为网络协议server.sin_port htons(port_server); // 绑定服务器端口server.sin_addr.s_addr inet_addr(ip_server.c_str()); // 实现ip的动态绑定// 客户端不用通过bind函数显性绑定套接字// 因为服务器先启动已经获得了套接字只要绑定服务器的ip和端口就能使用这个套接字// 向服务器发送信息std::string buffer;ssize_t n sendto(sock_fd, buffer.c_str(), buffer.size(), 0, (struct sockaddr *)server, sizeof(server));// 从服务端获取信息char buff_r[1024];struct sockaddr_in client;socklen_t len sizeof(client);ssize_t m recvfrom(sock_fd, buff_r, sizeof(buff_r) - 1, 0, (struct sockaddr *)client, len);
} 客户端进行套接字编程的流程 通过socket函数获取套接字其中SOCK_DGRAM对应UDP协议绑定服务器端口和服务器ip地址直接进行和服务器的IO通信 服务端和客户端Socket编程的异同
相同的是都需要调用socket函数来获取套接字设置网络协议为AF_INET和SOCK_DGRAM并且需要设置sockaddr_in结构体初始化这个结构体的内置变量。均共用一套IO的接口sendto和recvfrom。不同的是服务端的IP地址设置为INADDR_ANY表示可以绑定多个IP地址这也符合服务器需要和多台客户端进行IO的特性。另外服务端需要显性地绑定socket_fd套接字文件描述符和sockaddr_inIPV4套接字结构。而客户端需要绑定唯一一个服务器的IP并且不需要显性的绑定socket_fd和sockaddr_in。 1.2.2.TCP套接字编程
TCP协议是面向连接的所以与UDP套接字流程相比除了绑定套接字TCP需要在通信之前先建立连接具体来说就是服务器监听客户端发出链接请求请求接着客户端发出connect请求最终服务器接收请求获取一个通信的套接字最终完成链接的建立。接着再进行IO通信
// TCP服务器
{// 创建监听套接字int listen_sock socket(AF_INET, SOCK_STREAM, 0);// 定义并配置本地struct sockaddr_in local;bzero(local, sizeof(local));local.sin_family AF_INET;local.sin_port htons(_port);local.sin_addr.s_addr INADDR_ANY;int n ::bind(listen_sock, (struct sockaddr *)local, sizeof(local));// TCP是面向连接的需要监听client的链接int m listen(listen_sock, 5); // 对listen这个套接字进行监听是否完成链接设置全连接队列为5// 获取连接struct sockaddr_in peer;socklen_t len sizeof(peer);// accept返回的新的套接字通信套接字int sock_fd accept(_listen_sock, (struct sockaddr *)peer, len); // 用于数据通信accept未接收会阻塞未完成通信// 通过read、write函数进行IO通信std::string buffer;ssize_t m write(sock_fd, buffer.c_str(), buffer.size());char buffer_read[1024];ssize_t n read(sock_fd, buffer_read, sizeof(buffer_read));
} TCP服务端套接字编程的流程 创建监听的套接字然后设置协议为AF_INET和SOCK_STREAMTCP专用定义并配置套接字结构体最后进行监听套接字和网络套接字的结构体绑定进行监听在此期间等待客户端的connect请求设置网络套接字来接收客户端的信息并通过accept函数获取到新的通信套接字进行通信IO // TCP客户端
{// 创建套接字int sock_fd socket(AF_INET, SOCK_STREAM, 0);// 绑定服务器struct sockaddr_in server;server.sin_family AF_INET;server.sin_port htons(server_port);inet_pton(AF_INET, server_ip.c_str(), server.sin_addr);// TCP链接服务器int n connect(sock_fd, (struct sockaddr *)server, sizeof(server));// 通过read、write函数进行IO通信std::string buffer;ssize_t m write(sock_fd, buffer.c_str(), buffer.size());char buffer_read[1024];ssize_t n read(sock_fd, buffer_read, sizeof(buffer_read));
} TCP客户端套接字编程流程 创建套接字并将网络套接字结构体绑定到服务器调用connect发起链接服务器的请求此时处于服务端监听状态完成链接进行IO通信 到了这里我们已经知道如何用代码来构建UDP、TCP通信最基本的架构了而TCP是面向连接的这也体现在listen、connect、accept这三个函数中跟三次握手紧密相关但不等同。 如图为TCP中服务端和客户端建立通信的过程。
2.理解Socket套接字编程结构
我们在1.2中学习了如何搭建Socket套接字编程的结构但是我们还不知道什么是Socket、什么是sockaddr_in和为什么要将sockaddr_in类型强转为struct sockaddr*等等所以在有了对Socket编程的使用理解的基础上我们来讲一下原理
2.1.网络字节序
我们知道主机的地址排布也就是字节序是可能存在不同的大端机的字节序排列为高地址小端机的字节序排列为低地址那么这样就会导致在网络通信时字节序读取不一致导致数据不一致问题。 例如在大端机中32位整数0x12345678地址排布为78563412小端机则表示为12345678 所以为了统一字节序的读取在套接字编程中需要对网络字节序进行规定以大端字节序为网络字节序标准进行读取。我们在回到我们的代码中
local.sin_port htons(port); // htons即为字节序转换函数
而这些htons函数为系统提供的转换字节序的接口函数
#include arpa/inet.h//必须包含的头文件
// 主机序列转网络序列
uint32_t htonl(uint32_t hostlong);//将主机上unsigned int类型的数据转换成对应网络字节序
uint16_t htons(uint16_t hostshort);//将主机上unsigned short类型的数据转换成对应网络字节序
// 网络序列转主机序列
uint32_t ntohl(uint32_t netlong);//将从网络中读取的unsigned int类型的数据转换成当前计算机字节序
uint16_t ntohs(uint16_t netshort);//将从网络中读取的unsigned short类型的数据转换成当前计算机字节序 所以当我们在网络中获取了一些字节序数据我们需要对他进行大端字节序的转换成符合本机的字节序列。 这里即为将网络获取的数据字节序转化为本机的数据字节序而htons即为将本机的字节序数据转化为网络字节序大端
2.2.网络套接字结构体
我们之前在1.2.提及了一个新名称“网络套接字结构体”而这个结构体用于标识网络通信的端点包括IP地址、端口号和地址族等信息。
// 通用网络套接字结构
struct sockaddr
{__SOCKADDR_COMMON(sa_); /* Common data: address family and length. */char sa_data[14]; /* Address data. */
};// 网络套接字结构
struct sockaddr_in
{__SOCKADDR_COMMON(sin_);in_port_t sin_port; /* Port number. */struct in_addr sin_addr; /* Internet address. *//* Pad to size of struct sockaddr. */unsigned char sin_zero[sizeof(struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof(in_port_t) -sizeof(struct in_addr)];
};如图我们在网络进行IO通信时就是传输这个通用结构体对象sockaddr所以我们在1.2.中的代码中也经常看到类型转换为struct sockaddr *。而这里也可以看作是C语言实现的多态其中sockaddr为基类、sockaddr_in和sockaddr_un为派生类。 3.文件socket系统网络
66-2小时33分