1.socket基本概念介绍
socket中文是插座的意思,套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。socket通信过程主要分为客户端和服务器端,在实现socket通信过程中不可或缺的五类基本信息:服务器端的IP地址、服务器端的端口号、客户端的IP地址、客户端的端口号以及客户端与服务器端互相约定的通信协议。TCP提供了流和数据报两种通信机制,所以分为流套接字和数据报套接字。
2.socket编程原理
socket通信主要使用的两种协议分别是面向连接的TCP/IP协议以及无连接的UDP通讯协议。
1).TCP通信流程
基于TCP的socket编程的服务器端流程:
创建流套接字(socket)
将套接字绑定到一个本地地址和端口上(bind)
将套接字设定为监听模式,准备接收客户请求(listen)
等待客户端请求到来,等请求到来之后,接受连接请求,返回一个新的套接字(accept)
用返回的套接字和客户端进行通信,收发信息(send/recv)
返回,等待另一客户端请求
关闭套接字
基于TCP的socket编程的客户端流程:
创建流套接字(socket)
向服务器发送连接请求(connect)
和服务器端进行通信(send/recv)
关闭套接字
2).UDP通信流程
基于UDP的socket编程接收端:
创建数据报套接字(socket)
将套接字绑定到本地地址和端口上(bind)
等待接收数据(recvfrom)
关闭套接字
基于UDP的socket编程发送端:
创建数据报套接字(socket)
等待接收数据(sendto)
关闭套接字
说明:
每个 socket 被创建后,都会分配两个缓冲区,即输入缓冲区和输出缓冲区。在数据传输的过程中,read/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。write/recv() 函数也是从输入缓冲区中读取数据,而不是直接从网络中读取。输入输出缓冲区的默认大小一般都是 8K,可以通过 getsockopt() 函数获取。
3.通信协议制定
协议(Protocol)就是网络通信的约定,通信的双方必须都遵守才能正常收发数据。协议有很多种,例如 TCP、UDP、IP 等,通信的双方必须使用同一协议才能通信。协议是一种规范,由计算机组织制定,规定了很多细节,例如,如何建立连接,如何相互识别等。
所谓协议族(Protocol Family),就是一组协议(多个协议)的统称。最常用的是 TCP/IP 协议族,它包含了 TCP、IP、UDP、Telnet、FTP、SMTP 等上百个互为关联的协议,由于 TCP、IP 是两种常用的底层协议,所以把它们统称为 TCP/IP 协议族。
TCP通信socket自定义协议实现:相对于发送较大的文件或者图片的条件下,C语言实现一般可通过结构体的方式实现文件传输,C++一般可通过类来实现文件传输,但是需要注意的是两者在传输过程中,客户端和服务器端使用的协议必须一致,例如客户端以二进制的形式发送文件,服务器端就需要以二进制的形式接受并且保存文件,从而保证文件传输过程中的准确性。
4.相关函数介绍:
1).头文件
#include <sys/types.h>
#include <sys/socket.h>
2).socket函数
socket函数用于创建一个新的socket。socket的创建时socket通信的第一步,也是客户端和服务端都必须要执行的操作。
函数声明:
int socket(int domain, int type, int protocol);
参数说明:
domain:用来指明此socket对象所使用的地址簇或者协议簇,一般IPV4通信值为AF_INET,IPV6通信值为AF_INET6。
type:socket类型,TCP的类型为SOCK_STREAM,UDP为SOCK_DGRAM,SOCK_RAW为远是借口。
protocol:标识采用协议簇中的哪一种协议,一般设置为0。
3).bind函数
函数声明:
int bind(int _fd, const struct sockaddr *address, socket_t address_len);
参数说明:
_fd:socket函数创建的socket文件描述符。
address:sockaddr 结构指针。
address_len:绑定的地址长度,一般用sizeof。
4).listen函数
函数声明:
int listen(int _fd,int _n);
参数说明:
_fd:绑定了IP以及端口信息的socket文件描述符。
_n:请求排队的最大长度,当有多个客户端连接服务器时,这个值可以控制等待连接数量的最大值。
5).connect函数
函数声明:
int connect(int _fd,const struct sockaddr *address, socket_t address_len);
说明:客户端发起连接函数。
6).accept函数
函数声明;
int accept((int _fd,const struct sockaddr *address, socket_t address_len);
说明:服务器端接收数据的函数。
7).close函数
函数声明:
int close(int _fd);
5.阻塞模式
简单的来说,阻塞模式缓冲区的大小有关,发送端发送数据,若缓冲区被数据填满,发送端将不会再继续发送,等接收端从缓冲区中取出数据,数据取出之后,发送端才能继续发送。
接收端也是同样道理,接收端在缓冲区读取数据,只有缓冲区中有数据的时候,才能读取,若缓冲区没有数据,就需要等待发送端发送数据给缓冲区,接收端这边才能读取数据。