文件目录
一、socket介绍
Socket(套接字)是计算机网络中的一个重要概念,它指的是一种用于网络通信的编程接口。以下是关于Socket的详细解释:
一、定义与功能
- 定义:Socket是应用层与传输层之间的接口,它提供了一种标准的通信方式,使得不同的程序能够在网络上进行数据交换。Socket可以被视为网络通信的端点,它在网络上标识了一个通信链路的两端,并提供了通信双方所需的接口和功能。
- 功能:Socket允许应用程序通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。它允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。
二、工作原理
Socket的工作原理可以简单概括为以下几个步骤:
- 创建Socket:应用程序通过调用socket()函数创建一个Socket对象,并指定Socket的类型(如TCP或UDP)。
- 绑定地址和端口(仅服务器端):服务器端通过调用bind()函数将Socket对象与一个特定的IP地址和端口号绑定,这个端口就是服务器的标识,用于在网络上与其他主机建立连接。
- 监听连接(仅服务器端):服务器端通过调用listen()函数开始监听来自客户端的连接请求。
- 连接请求(客户端):客户端通过调用connect()函数向服务器发送连接请求,指定服务器的IP地址和端口号。
- 接受连接(服务器端):当服务器端监听到来自客户端的连接请求后,通过调用accept()函数接受连接请求,并返回一个新的Socket对象,用于与客户端进行通信。
- 数据传输:一旦建立连接,服务器和客户端就可以通过各自的Socket对象进行数据传输。它们通过读取和写入Socket对象上的数据流来发送和接收数据。
- 关闭连接:当通信完成或者出现错误时,可以通过关闭Socket对象来结束连接,释放资源。
三、类型
Socket主要分为两种类型:
- TCP Socket:基于TCP协议,提供面向连接的、可靠的、字节流的服务。在TCP协议中,建立连接通常需要进行三次握手,以保证数据的可靠传输。
- UDP Socket:基于UDP协议,提供无连接的、不可靠的、数据报的服务。UDP协议不保证数据的可靠性,但传输速度较快,适用于实时性要求较高的场景。
四、socket在本地进程间通讯应用
Socket(套接字)虽然主要用于不同主机之间的网络通信,但在同一主机上,进程间通信(IPC)也可以使用Socket,尤其是当需要模拟网络环境下的通信行为时。不过,在同一主机上进行进程间通信时,更常用的方式可能包括管道、消息队列、共享内存等。
二、socket本地进程间通讯实现
1.服务端
代码如下(示例):
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/un.h>
#include <signal.h>
int sockfd = 0;
int fd = 0;
void hander(int sig)
{
puts("关闭socket");
if(sockfd)
close(sockfd);
if(fd)
close(fd);
puts("删除socket");
const char *socket_path = "/tmp/my_socket.sock"; // 假设这是你的socket文件路径
// 删除socket文件
if (unlink(socket_path) == -1) {
perror("unlink");
} else {
printf("Socket file %s deleted.\n", socket_path);
}
exit(0);
}
int main(int argc , const char* argv[])
{
// 注册信号处理函数
if(signal(SIGINT, hander) == SIG_ERR)
{
perror("signal");
return EXIT_FAILURE;
}
// 创建socket
sockfd = socket(AF_UNIX, SOCK_STREAM, 0); // AF_LOCAL 通常是 AF_UNIX 的别名
if (sockfd < 0)
{
perror("socket");
return EXIT_FAILURE;
}
// 准备通信地址(本地socket地址)
struct sockaddr_un addr = {};
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/my_socket.sock"); // 注意确保路径的唯一性和可访问性
socklen_t addrlen = sizeof(addr);
// 绑定socket和地址
if (bind(sockfd, (struct sockaddr *)&addr, addrlen) < 0)
{
perror("bind");
return EXIT_FAILURE;
}
// 开启监听
if (listen(sockfd, 5) < 0)
{
perror("listen");
return EXIT_FAILURE;
}
// 等待连接
fd = accept(sockfd, (struct sockaddr *)&addr, &addrlen);
if (fd < 0)
{
perror("accept");
return EXIT_FAILURE;
}
char buf[4096] = {};
size_t buf_size = sizeof(buf) - 1; // 留出空间给终止符
while (1)
{
fflush(stdout); // 刷新输出缓冲区
ssize_t ret_size = read(fd, buf, buf_size);
if (ret_size > 0)
{
buf[ret_size] = '\0'; // 加上终止符
if (strncmp(buf, "quit", 4) == 0) // 使用 strncmp 来比较前 4 个字符
{
printf("通讯结束\n");
break;
}
printf("\nrecv:%s\n>>>>", buf);
if (fgets(buf, buf_size, stdin) != NULL)
{
// 去掉可能的换行符
buf[strcspn(buf, "\n")] = 0;
write(fd, buf, strlen(buf)); // 不需要发送终止符
if (strncmp(buf, "quit", 4) == 0)
{
printf("通讯结束\n");
break;
}
}
}
else if (ret_size == 0)
{
// 对端关闭连接
printf("对端关闭连接\n");
break;
}
else
{
// 错误处理
perror("read");
break;
}
}
// 关闭socket
close(fd);
close(sockfd);
// 删除socket文件
unlink(addr.sun_path);
return 0;
}
2.客户端
代码如下(示例):
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/un.h>
int main(int argc , const char* argv[])
{
// 创建socket
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket");
return EXIT_FAILURE;
}
// 准备通信地址(本地socket地址)
struct sockaddr_un addr = {};
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/my_socket.sock");
// 连接
if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
perror("connect");
return EXIT_FAILURE;
}
char buf[4096] = {};
size_t buf_size = sizeof(buf) - 1; // 留出空间给终止符
while(1)
{
fflush(stdout); // 刷新输出缓冲区
printf(">>>");
if(fgets(buf, buf_size, stdin) != NULL)
{
// 去掉可能的换行符
buf[strcspn(buf, "\n")] = 0;
write(sockfd, buf, strlen(buf)); // 不需要发送终止符
}
ssize_t ret_size = read(sockfd, buf, buf_size);
if(ret_size > 0)
{
buf[ret_size] = '\0'; // 添加终止符
// 检查是否收到 "quit"
if (strstr(buf, "quit") != NULL)
{
printf("通讯结束\n");
break;
}
printf("\nrecv:%s\n", buf);
}
else if (ret_size == 0)
{
// 对端关闭连接
printf("对端关闭连接\n");
break;
}
else
{
// 错误处理
perror("read");
break;
}
}
// 关闭socket
close(sockfd);
return 0;
}