163人参与 • 2024-07-31 • Unix
实验目标:
1 实现基于流的unix域套接字通信cs模型
2 实现基于数据报的unix域套接字通信cs模型
3 可以观察到cs两端的完整启动退出流程,为了实现这一目标仅进行一次通信
实验心得:
1 使用unlink避免地址冲突 清理资源
2 传统udp在首次sendto时系统临时分配端口,在套接字关闭|程序终止|显式解绑时端口生命周期结束,而unix域套接字则需要手动绑定,否则客户端无法收到服务器的回信
3 复制文件路径时,sun_path的长度无法更改,容易出现越界的情况
基于流:
#define _gnu_source
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <string.h>
#include <unistd.h>
#define sock_path "/home/u22/socket/addr1"
// 服务端
int main()
{
int server_sockfd, client_sockfd;
struct sockaddr_un server_sockaddr, client_sockaddr;
memset(&server_sockaddr, 0, sizeof(server_sockaddr));
memset(&client_sockaddr, 0, sizeof(client_sockaddr));
socklen_t client_sockaddr_len = sizeof(client_sockaddr);
ssize_t send_bytes, recv_bytes;
char send_buf[1024] = "server say : how can i help you today ?";
char recv_buf[1024] = {0};
// unix域套接字 使用流式传输,不能叫tcp
server_sockfd = socket(af_unix, sock_stream, 0);
if (server_sockfd == -1)
{
perror("socket");
}
server_sockaddr.sun_family = af_unix;
strcpy(server_sockaddr.sun_path, sock_path);
// 为什么要删除这个文件?因为再次启动代码将无法访问这个文件
unlink(sock_path);
if ((bind(server_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr))) == -1)
{
perror("bind");
}
if (listen(server_sockfd, 16) == -1)
{
perror("listen");
}
printf("waiting for connect...\n");
// accept返回后将收到客户端地址信息
client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_sockaddr, &client_sockaddr_len);
if (client_sockfd == -1)
{
perror("accept");
}
// 同tcp一样 recv send使用accept返回的socket通信
recv_bytes = recv(client_sockfd, recv_buf, sizeof(recv_buf), 0);
if (recv_bytes == -1)
{
perror("recv");
}
if (recv_bytes > 0)
{
printf("%s\n", recv_buf);
}
send_bytes = send(client_sockfd, send_buf, strlen(send_buf), 0);
if (send_bytes == -1)
{
perror("send");
}
if (send_bytes > 0)
{
printf("%s\n", send_buf);
}
close(client_sockfd);
close(server_sockfd);
printf("server close\n");
//用完了 还要删一遍
unlink(sock_path);
return 0;
}
#define _gnu_source
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <string.h>
#include <unistd.h>
#define sock_path "/home/u22/socket/addr1"
//客户端
int main()
{
int client_sockfd;
struct sockaddr_un server_sockaddr;
memset(&server_sockaddr, 0, sizeof(server_sockaddr));
ssize_t send_bytes, recv_bytes;
char send_buf[1024] = "client say : hello server !";
char recv_buf[1024] = {0};
//创建基于流的unix域套接字
client_sockfd = socket(af_unix, sock_stream, 0);
if (client_sockfd == -1)
{
perror("socket");
}
server_sockaddr.sun_family = af_unix;
strcpy(server_sockaddr.sun_path, sock_path);
//尝试连接server
printf("connect server...\n");
if ((connect(client_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr))) == -1)
{
perror("connect");
}
//与tcp一样 使用socket()返回的socket通信
send_bytes = send(client_sockfd, send_buf, strlen(send_buf), 0);
if (send_bytes == -1)
{
perror("send");
}
printf("%s\n", send_buf);
recv_bytes = recv(client_sockfd, recv_buf, sizeof(recv_buf), 0);
if (recv_bytes == -1)
{
perror("recv");
}
printf("%s\n", recv_buf);
close(client_sockfd);
printf("client close\n");
return 0;
}
基于数据报:
#define _gnu_source
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <string.h>
#include <unistd.h>
#define sock_path "/home/u22/socket/addr2"
int main()
{
int server_sockfd;
struct sockaddr_un server_sockaddr, client_sockaddr;
memset(&server_sockaddr, 0, sizeof(server_sockaddr));
memset(&client_sockaddr, 0, sizeof(client_sockaddr));
socklen_t client_sockaddr_len = sizeof(client_sockaddr);
ssize_t send_bytes, recv_bytes;
char send_buf[1024] = "server say : how can i help you today ?";
char recv_buf[1024] = {0};
// unix域套接字 使用数据报传输,不能叫udp
server_sockfd = socket(af_unix, sock_dgram, 0);
if (server_sockfd == -1)
{
perror("socket");
}
// 无法再次访问此文件,必须删除
unlink(sock_path);
server_sockaddr.sun_family = af_unix;
// 容易越界,本系统为108字节
strncpy(server_sockaddr.sun_path, sock_path, sizeof(server_sockaddr.sun_path));
// 不bind,peer使用sendto也可以正常发送,但是本endpoint无法接收
if ((bind(server_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr))) == -1)
{
perror("bind");
}
printf("waiting for recv...\n");
// 接收的客户端地址信息存在client_sockaddr中,供sendto使用
recv_bytes = recvfrom(server_sockfd, recv_buf, sizeof(recv_buf),
0, (struct sockaddr *)&client_sockaddr, &client_sockaddr_len);
if (recv_bytes == -1)
{
perror("recv");
}
if (recv_bytes > 0)
{
printf("%s\n", recv_buf);
}
send_bytes = sendto(server_sockfd, send_buf, strlen(send_buf),
0, (struct sockaddr *)&client_sockaddr, client_sockaddr_len);
if (send_bytes == -1)
{
perror("send");
}
if (send_bytes > 0)
{
printf("%s\n", send_buf);
}
close(server_sockfd);
printf("server close\n");
// 用完删除sock_path这个文件
unlink(sock_path);
return 0;
}
#define _gnu_source
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <string.h>
#include <unistd.h>
// 客户端使用的socket文件
#define sock_path_c "/home/u22/socket/addr3"
// 服务器使用的socket文件
#define sock_path_s "/home/u22/socket/addr2"
// 客户端
int main()
{
int client_sockfd;
struct sockaddr_un server_sockaddr, client_sockaddr;
memset(&server_sockaddr, 0, sizeof(server_sockaddr));
memset(&client_sockaddr, 0, sizeof(client_sockaddr));
socklen_t server_sockaddr_len = sizeof(server_sockaddr);
ssize_t send_bytes, recv_bytes;
char send_buf[1024] = "client say : hello server !";
char recv_buf[1024] = {0};
// 基于数据报的unix域套接字
client_sockfd = socket(af_unix, sock_dgram, 0);
if (client_sockfd == -1)
{
perror("socket");
}
// 必须删除,否则下次不让用
unlink(sock_path_c);
client_sockaddr.sun_family = af_unix;
// 容易越界,本系统为108
strncpy(client_sockaddr.sun_path, sock_path_c, sizeof(client_sockaddr.sun_path));
// 传统udp在首次sendto时系统临时分配端口,在套接字关闭|程序终止|显式解绑时端口生命周期结束
// 而unix域套接字则需要手动绑定
if ((bind(client_sockfd, (struct sockaddr *)&client_sockaddr, sizeof(client_sockaddr))) == -1)
{
perror("bind");
}
server_sockaddr.sun_family = af_unix;
// 容易越界,本系统为108
strncpy(server_sockaddr.sun_path, sock_path_s, sizeof(server_sockaddr.sun_path));
printf("send message\n");
// 向服务器发送信息,由server_sockaddr指定地址
send_bytes = sendto(client_sockfd, send_buf, strlen(send_buf),
0, (struct sockaddr *)&server_sockaddr, server_sockaddr_len);
if (send_bytes == -1)
{
perror("send");
}
if (send_bytes > 0)
{
printf("%s\n", send_buf);
}
// 两个null是服务器的地址信息和长度,不需要则设为null
recv_bytes = recvfrom(client_sockfd, recv_buf, sizeof(recv_buf),
0, null, null);
if (recv_bytes == -1)
{
perror("recv");
}
if (recv_bytes > 0)
{
printf("%s\n", recv_buf);
}
close(client_sockfd);
printf("client close\n");
// 用完必须删除文件
unlink(sock_path_c);
return 0;
}
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论