socket套接字

简介: socket套接字

1. 什么是socket套接字

套接字就像一个插座,插座需要一个插头来连接双方才能通电,而socket通信也需要两个端,一个服务端一个客户端。一般来说,服务端是被动的,客户端是主动的,也就是说服务端应该先启动,启动之后就被动的去准备被(客户端)连接以提供服务,而客户端需要服务的时候就主动去连接服务器端。

实际上,socket编程就是网络IO编程,同样也是读写操作,只不过是对网络进行读写,通过read/write和文件描述符来完成读写。我们在创建套接字的时候,会得到文件描述符,然后就可以通过这个文件描述符来完成读写操作。

实际上,我们在进程间通信时用的管道也是在内核中分配一块缓冲区,这个缓冲区是用一个环形队列来维护的,本质是内存中的一块存储空间,在管道的读写两端分别对应一个文件描述符,操作读端的文件描述符fd就相当于操作内核缓冲区。

套接字创建成功后,也会得到一个文件描述符fd,通过fd来操作一块内核缓冲区。在服务器端创建一个套接字,就会得到一个内核缓冲区和文件描述符,这个缓冲区分为读写两部分。在客户端发数据使用的是write操作,当我们执行write(fd)的时候,数据并不是直接写到网上的,而是先写到文件描述符对应的内核缓冲区中的写缓冲区部分,写缓冲区中只要有数据就会自动发送到服务器端的读缓冲区中,服务器端通过read就可以把数据读出。我们所做的只有read和write操作,其他操作都是由操作系统完成的。需要注意的一点是,读缓冲区中的数据读走了之后就没有了,和管道一样。

套接字对应的文件描述符默认也是阻塞的,实际上阻塞是文件描述符对应的文件所拥有的性质,而不是read/write的属性,这两个函数只负责读取或者写数据,即阻塞性质是对文件描述符所对应的文件类型而言的。

2. socket编程

  • socket是一套网络通信的函数接口
  • socket内封装了传输层协议
  • TCP
  • UDP

socket编程就是使用别人提供的一套网络通信接口进行编程。比如说我们使用浏览器搜索内容,浏览器使用的是HTTP协议,而HTTP协议再往下封装的就是TCP协议。

在套接字编程时需要IP和Port:

  • IP地址:在网络环境中,需要IP来定位一台主机
  • 端口号Port:在一台主机上,需要Port来定位一个进程
  • IP:Port

3. 网络字节序

  • 大端:网络字节序,数据的高位字节存储在内存的低地址。
  • 小端:主机字节序,数据的高位字节存储在内存的高位地址。常见的主机数据都是小端存储。

函数介绍:

#include <arpa/inet.h>

(1) 主机字节序转网络字节序

uint16_t htons(uint16_t hostshort); //端口
uint32_t htonl(uint32_t hostlong); //IP

(2) 网络字节序转主机字节序

uint16_t ntohs(uint16_t netshort); //端口
uint32_t ntohl(uint32_t netlong); //IP

假如说我们要将小端字节序转换为大端字节序,如果主机是小端字节序,这些函数将参数做相应的大小端转换后返回,如果主机是大端字节序,这些函数将不做任何变换,将参数原封不动的返回。

常见的文件字节序:

  • Adobe PS — Big Endian
  • BMP — Little Endian
  • GIF — Little Endian
  • JPEG — Big Endian
  • MacPaint — Big Endian
  • RTF — Little Endian

注:在Java以及所有的网络通讯协议都是使用Big-Endian编码。

4. IP地址转换函数

指定IP转换为点分十进制字符串

  • 本地IP转网络字节序:字符串 —> int(大端方式存储)
int inet_pton(int af, const char* src, void* dst);
  • af:地址簇协议
  • src:点分十进制IP
  • dest:传出参数,转换后的int整形的存放地址
  • 网络字节序转本地IP:int —> 字符串
const char *inet_ntop(int af, const void* src, char* dst, socklen_t size);

5. sockaddr数据结构

  • sockaddr
  • sockaddrin
  • sockaddrun
struct sockaddr { 
  /* address family, AF_xxx */
  sa_family_t sa_family; 
  /* 14 bytes of protocol address */
  char sa_data[14];     
};
struct sockaddr_in {
  __kernel_sa_family_t sin_family;   // 地址族协议     
  __be16 sin_port;  // 端口
  struct in_addr sin_addr;   // IP地址        
  unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];
};
struct in_addr {
  __be32 s_addr;
};

IPv4地址用socketaddr_in结构体表示,包括16位端口号和32位IP地址,IPv6地址用socketaddr_in6结构体表示,包括16位端口号、128位IP地址和一些控制字段。

6. 网络套接字函数

(1) 创建套接字

int socket(int domain, int type, int protocol);
  • 创建一个套接字
  • domin
  • AF_INET:这是大多数用来产生socket的协议,使用TCP或UDP来传输,使用IPv4的地址;
  • AF_INET6:使用IPv6的地址;
  • AF_UNIX:本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器端都在同一台机器上的时候使用;
  • type
  • SOCK_STREAM:流式协议,这个协议是按照顺序的、可靠的、数据类型完整的、基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输的;
  • SOCK_DGRAM:报式协议,这个协议式无连接的、固定长度的传输调用,该协议是不可靠的,使用UDP进行传输;
  • SOCK_SEQPACKET:该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输,必须把这个包完整的接收才能进行读取;
  • SOCK_RAW:socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议,ping以及traceroute都使用该协议;
  • SOCK_RDM:这个类型使用较少,在大部分操作系统上没有实现,它提供给数据链路层使用,不保证数据包的顺序;
  • protocol:设置0表示使用默认协议; 协议,常见的协议有IPPROTO_TCP、IPPTOTO_UDP、 IPPROTO_SCTP、IPPROTO_TIPC他们分别对应这TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。当protocol为0时,会自动选择type类型对应的默认协议;
  • 返回值为文件描述符(套接字),即创建好的socket套接字的文件描述符。On success, a file descriptor for the new socket is returned. On error, -1 is returned, and errno is set appropriately.

(2) 绑定

int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
  • 将本地的IP和端口号与创建出来的套接字绑定,将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。
  • sockfd:创建出的文件描述符
  • addr:端口和IP
  • addrlen:addr结构体的长度,sizeof(addr)

(3) 监听

int listen(int sockfd, int backlog);
  • 设置同时连接到服务器的客户端的个数,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接等待状态,如果接收到更多的连接请求就忽略。
  • sockfd:socket函数创建出来的文件描述符;
  • backlog:同时能连接的最大数量,最大值为128;

(4) 接受连接

int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
  • 阻塞等待客户端连接请求,并接受连接。
  • sockfd:文件描述符,使用socket创建出来的文件描述符;
  • 监听的文件描述符;
  • addr:存储客户端的端口和IP,是一个传出参数;
  • addrlen:传入传出参数(值 - 结果),传入sizeof(addr)的大小,函数返回时返回真正接收到地址结构体的大小;
  • 函数返回值是一个套接字,对应客户端,服务器端与客户端进程通信使用accept的返回值对应的套接字。

(5) 连接

int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
  • 客户端需要调用connect()函数连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。
  • sockfd:套接字;
  • addr:传入参数,指定服务器端地址信息,服务器端的IP和端口;
  • addrlen:第二个参数addr的长度;

7. TCP通信流程图

相关文章
|
6月前
|
网络协议 安全 网络安全
Python网络编程详解:Socket套接字的使用与开发
探索Python网络编程:本文详述Socket套接字,关键组件用于设备间通信。理解Socket类型(TCP/UDP),学习创建、绑定、监听、发送/接收数据步骤。示例展示服务端和客户端实现,及Socket聊天室应用。了解并发处理、错误处理和网络安全。通过学习,提升网络应用开发技能。参考书籍深入学习。
175 2
|
6月前
套接字(socket)的端点表示
套接字(socket)的端点表示
71 8
|
6月前
|
网络协议 安全 Unix
UNIX域套接字(Unix Domain Socket,UDS)之所以高效
UNIX域套接字(Unix Domain Socket,UDS)之所以高效
480 3
|
6月前
|
监控 安全 Unix
UNIX域套接字(Unix Domain Socket)在安全性和隐私性
UNIX域套接字(Unix Domain Socket)在安全性和隐私性
278 2
|
6月前
|
网络协议 Java Unix
套接字(Socket)
套接字(Socket)
70 3
|
6月前
|
算法 Unix
socket套接字选项getsockopt&setsockopt
setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。在Unix网络编程中通常用到getsockopt和setsockopt两个函数来获取和设置套接口的选项。getsockopt()函数用于获取任意类型、任意状态套接口的选项当前值,并把结果存入optval。
95 0
|
存储 网络协议 Unix
网络基础:socket套接字
网络基础:socket套接字
93 0
|
24天前
|
Java
[Java]Socket套接字(网络编程入门)
本文介绍了基于Java Socket实现的一对一和多对多聊天模式。一对一模式通过Server和Client类实现简单的消息收发;多对多模式则通过Server类维护客户端集合,并使用多线程实现实时消息广播。文章旨在帮助读者理解Socket的基本原理和应用。
19 1
|
2月前
|
网络协议
关于套接字socket的网络通信。&聊天系统 聊天软件
关于套接字socket的网络通信。&聊天系统 聊天软件
|
3月前
|
网络协议 Java
一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例
这篇文章全面讲解了基于Socket的TCP网络编程,包括Socket基本概念、TCP编程步骤、客户端和服务端的通信过程,并通过具体代码示例展示了客户端与服务端之间的数据通信。同时,还提供了多个案例分析,如客户端发送信息给服务端、客户端发送文件给服务端以及服务端保存文件并返回确认信息给客户端的场景。
一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例