首页 > 其他分享 >C语言UNIX域套接字CS模型

C语言UNIX域套接字CS模型

时间:2024-03-24 10:34:09浏览次数:13  
标签:sockaddr 域套 send server UNIX client sockfd C语言 recv

实验目标:

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;
}

标签:sockaddr,域套,send,server,UNIX,client,sockfd,C语言,recv
From: https://blog.csdn.net/qq_43689451/article/details/136983093

相关文章

  • c语言学习路线
    学习C语言可以按照以下路线进行:基础知识:了解C语言的基本语法和特性学习C语言的数据类型、控制流和函数熟悉指针和内存管理的概念数组和字符串:学习如何操作数组和字符串掌握数组和字符串的常见操作和算法熟悉C语言中的字符处理函数结构体和指针:理解结构体的概念和用法......
  • 快速排序(C语言)
    快速排序(英语:Quicksort),又称分区交换排序,简称「快排」,是一种被广泛运用的排序算法。快速排序的工作原理是通过分治的方式来将一个数组排序。快速排序分为三个过程:将数列划分为两部分(要求保证相对大小关系);递归到两个子序列中分别进行快速排序;不用合并,因为此时数列已经完全有序......
  • # c语言程序设计——实验报告二
    实验项目名称:实验报告2数据描述实验项目类型:验证性实验日期:2024年3月21日一、实验目的1、掌握C语言数据类型,熟悉如何定义一个整型、字符型和实型的变量,以及对它们赋值的方法。2、掌握不同数据类型之间赋值的规律。3、学会使用C的有关算术运算符,以及包含这些运算符的......
  • C语言作业(二)
    1.在数组中查找某个数字#include<stdio.h>intmain(){intarr[]={1,2,3,4,5,6,8,9,10,11};intk=7;intsz=sizeof(arr)/sizeof(arr[0]);//求解数组的元素个数intleft=0;intright=sz-1;while(left<=right){......
  • C语言作业(五)
     1.逆序字符串函数//写一个函数,来逆序一个字符串的内容#include<stdio.h>#include<string.h>#include<assert.h>voidreverse(char*str){assert(str);//保证指针的有效性intlen=strlen(str);char*left=str;//left指针指向第一个字符char*......
  • # c语言程序设计——实验报告一
    实验项目名称:实验一熟悉C语言运行环境实验项目类型:验证性实验日期:2023年3月14日一、实验目的下载安装Devc6.0程序。了解在该系统上如何进行编辑、编译、连接和运行一个C程序。通过运行简单的C程序了解C程序的特点。二、实验硬、软件环境Windows计算机、Devc6.0三、......
  • C语言for循环详细讲解
    引言:在上一篇博客中,我们介绍了关于C语言的一种循环,while循环,并介绍了其中的关键字及其例题,在本片帖子,我们将引入一种新的循环方式,名为for循环,那么它与while循环又有哪些相似之处和不同之处呢?让我们一起来探索一下。一.for循环的基本架构for循环时三种循环中使用最多的for循......
  • C语言:洛谷题目分享(4)小书童--凯撒密码和笨小猴
    目录1.前言2.俩道题目1.小书童--凯撒密码1.题目背景2.题目描述3.输入格式4.输出格式5.题解2.笨小猴1.题目描述2.输入格式3.输出格式4.题解3.小结1.前言哈喽大家好啊,今天我继续为大家分享洛谷题单的俩道题目,请大家多多支持喔~2.俩道题目1.小书童--凯撒密码......
  • c语言:日期识别1
    日期识别1任务描述X同学最近非常烦,因为他正面对一大堆日期数据愁眉不展,原因是那些日期书写的极其不规范,不仔细辨别根本认不清是哪一天。以下每个日期中的三个数,年月日的位置是不确定的,假设其中最大的数表示年份,1-12范围的数表示月份,1-31范围的数表示日期,如果月日的范围都......
  • 2024年C语言最新经典面试题汇总(1-10)
    C语言文章更新目录C语言学习资源汇总,史上最全面总结,没有之一C/C++学习资源(百度云盘链接)计算机二级资料(过级专用)C语言学习路线(从入门到实战)编写C语言程序的7个步骤和编程机制C语言基础-第一个C程序C语言基础-简单程序分析VS2019编写简单的C程序示例简单示例,VS2019调......