起源于Unix,Unix/Linux的基本理念之一是“一切皆文件”,可以使用“打开->读/写写/读->关闭”模式进行操作。 它是这种模式的一种实现,即一个特殊的文件,一些函数对其进行操作(读/写IO、打开、关闭)。
说白了,它是应用层和TCP/IP协议族之间进行通信的中间软件抽象层。 它是一组接口。 在设计模式上,实际上是一种门面模式,将复杂的TCP/IP协议族隐藏在接口的背后。 对于用户来说,一组简单的接口就足够了,允许组织数据以符合指定的协议。
注意:实际上,不存在层的概念。 它只是设计模式的一种应用,使编程变得更容易。 它是一个软件抽象层。 在网络编程中,我们使用了很多实现。
除了网络上不同主机之间的通信之外,套接字还可以用于实现同一主机上不同进程之间的通信,并且所建立的通信是双向通信。 进程通信和网络通信使用统一的,但地址结构和一些参数不同。
其主要流程如下:
1. 创建
创建,类型为 or,用于进程通信:
调用函数(),其原型如下:
int(int,int类型,int);
范围:
:指定协议族。 对于本地套接字,该值必须设置为枚举值;
type:指定套接字类型,可以设置为(流套接字)或(数据报套接字)
:指定特定协议,应设置为0
返回值是生成的套接字描述符。
对于本地来说,()是一个有序的、可靠的双向字节流,相当于在本地进程之间建立了一条数据通道; ()相当于单纯的发送消息,在进程通信过程中,理论上可能会出现信息丢失、复制、乱序到达的情况。 不过,由于是本地通信,不经过外部网络,所以这些情况发生的概率很小。
2. 设置参数
本地套接字的通信双方都需要有本地地址。 服务器的本地地址需要明确指定。 指定的方法是使用类型的变量
{
; //
字符[]; // 路径名
3. 绑定
绑定使用bind系统调用,其原型如下:
int 绑定(int, const *,);
范围
:服务器套接字描述符
:需要绑定的服务器本地地址
:本地地址的字节长度
4. 监控
服务器端套接字创建并赋予本地地址值(本例中为名称)后,需要监听,等待客户端连接并处理请求,使用系统调用进行监听,并使用系统调用接受客户端连接。 他们的原型如下:
int (int , int );
int (int, *, *);
范围
:代表服务器端描述符;
表示排队连接队列的长度(如果多个客户端同时连接,则需要排队);
当前连接的客户端的本地地址。 该参数是输出参数,是客户端传递过来的关于自身的信息;
指示当前连接的客户端的本地地址的长度(以字节为单位)。 该参数既是输入参数又是输出参数。 实施监测、验收和处理。
5. 连接
客户端需要 call()来连接服务器,其函数原型如下:
int (int, const *, );
范围
:客户端的套接字描述符
:当前客户端的本地地址,是一个类型变量
:表示本地地址的字节长度
5. 数据交互
客户端和服务器都必须就数据进行交互。 一个进程扮演客户端的角色,另一个进程扮演服务器的角色。 两个进程相互发送和接收数据。 这是基于本地套接字的进程通信。
循环读取客户端发送的消息。 当客户端不发送数据时,它会阻塞,直到数据到达。 如果想要多个连接并发处理,就需要创建一个线程,将每个连接交给对应的线程来并发处理。 接收到数据后,进行相应的处理,并将结果返回给客户端。 要发送和接收数据,需要使用 write 和 read 系统调用。 他们的原型是:
int 读取(int, char *, len);
int write(int, char *, len);
下面是一个本地进程间通信的简单例子:
1. 服务器
#include
#include
#include
#include
#define CAN_SERVICE "CAN_SERVICE"
int main(void)
{
int ret;
int len;
int accept_fd;
int socket_fd;
static char recv_buf[1024];
socklen_t clt_addr_len;
struct sockaddr_un clt_addr;
struct sockaddr_un srv_addr;
socket_fd=socket(PF_UNIX,SOCK_STREAM,0);
if(socket_fd<0)
{
perror("cannot create communication socket");
return 1;
}
// 设置服务器参数
srv_addr.sun_family=AF_UNIX;
strncpy(srv_addr.sun_path,CAN_SERVICE,sizeof(srv_addr.sun_path)-1);
unlink(CAN_SERVICE);
// 绑定socket地址
ret=bind(socket_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("cannot bind server socket");
close(socket_fd);
unlink(CAN_SERVICE);
return 1;
}
// 监听
ret=listen(socket_fd,1);
if(ret==-1)
{
perror("cannot listen the client connect request");
close(socket_fd);
unlink(CAN_SERVICE);
return 1;
}
// 接受connect请求
len=sizeof(clt_addr);
accept_fd=accept(socket_fd,(struct sockaddr*)&clt_addr,&len);
if(accept_fd<0)
{
perror("cannot accept client connect request");
close(socket_fd);
unlink(CAN_SERVICE);
return 1;
}
// 读取和写入
memset(recv_buf,0,1024);
int num=read(accept_fd,recv_buf,sizeof(recv_buf));
printf("Message from client (%d)) :%s\n",num,recv_buf);
// 关闭socket
close(accept_fd);
close(socket_fd);
unlink(CAN_SERVICE);
return 0;
}
2. 客户
#include
#include
#include
#include
#define CAN_SERVICE "CAN_SERVICE"
int main(void)
{
int ret;
int socket_fd;
char snd_buf[1024];
static struct sockaddr_un srv_addr;
// 创建socket
socket_fd=socket(PF_UNIX,SOCK_STREAM,0);
if(socket_fd<0)
{
perror("cannot create communication socket");
return 1;
}
srv_addr.sun_family=AF_UNIX;
strcpy(srv_addr.sun_path,CAN_SERVICE);
// 连接到服务器
ret=connect(socket_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("cannot connect to the server");
close(socket_fd);
return 1;
}
memset(snd_buf,0,1024);
strcpy(snd_buf,"message from client");
// 读取和写入
write(socket_fd,snd_buf,sizeof(snd_buf));
close(socket_fd);
return 0;
}
与本地套接字对应的是网络套接字,可以用来在网络上传输数据。 也就是说,它可以实现不同机器上的进程通信过程。 在TCP/IP协议中,IP地址的第一个字节是127,表示本地,因此可以使用IP地址为127.xxx的网络套接字来实现本地套接字通信。