IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> C语言:详细讲解基于tcp和udp的两种本地通信方式 -> 正文阅读

[网络协议]C语言:详细讲解基于tcp和udp的两种本地通信方式

一.本地通信(UNIX域套接字)

1.1概念

socket同样可以用于本地通信创建套接字时使用本地协议PF_UNIX(或PF_LOCAL)分为流式套接字和用户数据报套接字,区别还是有无连接常用于前后台进程通信。

使用的机构体

struct sockaddr_un {
    sa_family_t sun_family;               /* AF_UNIX */
    char        sun_path[108];            /* 路径及文件名 */
};

1.2TCP本地通信流程

服务器:

创建套接字 socket( )

填充服务器本地信息结构体 sockaddr_un

将套接字与服务器本地信息结构体绑定 bind( )

将套接字设置为被动监听状态 listen( )

阻塞等待客户端的连接请求 accept( )

进行通信 recv( )/send( ) 或 read( )/write( )

客户端:

创建套接字 socket( )

填充服务器本地信息结构体 sockaddr_un

发送客户端的连接请求 connect( )

进行通信 send( )/recv( )

1.3代码实现

代码说明:这就是一个循环应答的一个代码,来讲解本地通信

服务器代码
?

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define ERRLOG(errmsg) do{\
        printf("%s:%s:%d --", __FILE__, __func__, __LINE__);\
        perror(errmsg);\
        exit(-1);\
    }while(0)

int main(int argc, const char *argv[]){
    if(2 != argc){
        printf("Usage : %s <filename>\n", argv[0]);
        return -1;
    }

    //创建流式套接字
    int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(-1 == sockfd){
        ERRLOG("socket error");
    }

    //填充信息本地信息结构体
    struct sockaddr_un serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sun_family = AF_UNIX;
    strcpy(serveraddr.sun_path, argv[1]);

    socklen_t serveraddr_len = sizeof(serveraddr);

    //绑定
    if(-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){
        ERRLOG("bind error");
    }

    //监听
    if(-1 == listen(sockfd, 5)){
        ERRLOG("listen error");
    }

    //定义结构体保存对方的信息
    struct sockaddr_un clientaddr;
    memset(&clientaddr, 0, sizeof(clientaddr));
    socklen_t clientaddr_len = sizeof(clientaddr);

    int acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len);
    if(-1 == acceptfd){
        ERRLOG("accept error");
    }
    printf("客户端[%s]连接到服务器\n", clientaddr.sun_path);

    char buff[128] = {0};
    while(1){
        if(-1 == recv(acceptfd, buff, 128, 0)){
            ERRLOG("recv error");
        }
        printf("客户端[%s]发来数据[%s]\n", clientaddr.sun_path, buff);
        strcat(buff, "--hqyj");
        if(-1 == send(acceptfd, buff, 128, 0)){
            ERRLOG("send error");
        }
        memset(buff, 0, 128);
    }
    close(acceptfd);

    close(sockfd);

    return 0;
}

客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define ERRLOG(errmsg) do{\
        printf("%s:%s:%d --", __FILE__, __func__, __LINE__);\
        perror(errmsg);\
        exit(-1);\
    }while(0)

int main(int argc, const char *argv[]){
    if(2 != argc){
        printf("Usage : %s <filename>\n", argv[0]);
        return -1;
    }

    //创建流式套接字
    int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(-1 == sockfd){
        ERRLOG("socket error");
    }

    //填充服务器本地信息结构体
    struct sockaddr_un serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sun_family = AF_UNIX;
    strcpy(serveraddr.sun_path, argv[1]);

    socklen_t serveraddr_len = sizeof(serveraddr);


    //定义客户端本地信息结构体
    struct sockaddr_un clientaddr;
    memset(&clientaddr, 0, sizeof(clientaddr));
    clientaddr.sun_family = AF_UNIX;
    strcpy(clientaddr.sun_path,"tcp_client_file");
    socklen_t clientaddr_len = sizeof(clientaddr);

    //客户端需要绑定,否则服务器收不到客户端的文件名
    if(-1 == bind(sockfd, (struct sockaddr *)&clientaddr, clientaddr_len)){
        ERRLOG("bind error");
    }

    if(-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){
        ERRLOG("accept error");
    }
    printf("连接服务器成功\n");

    char buff[128] = {0};
    while(1){
        fgets(buff, 128, stdin);
        buff[strlen(buff)-1] = '\0';
        if(-1 == send(sockfd, buff, 128, 0)){
            ERRLOG("send error");
        }
        if(-1 == recv(sockfd, buff, 128, 0)){
            ERRLOG("recv error");
        }
        printf("应答[%s]\n", buff);
        memset(buff, 0, 128);
    }

    close(sockfd);

    return 0;
}

二UDP本地通信

2.1流程

服务器:

创建套接字 socket( )

填充服务器本地信息结构体 sockaddr_un

将套接字与服务器本地信息结构体绑定 bind( )

进行通信 recvfrom( ) / sendto( )

客户端:

创建套接字 socket( )

填充客户端本地信息结构体 sockaddr_un

将套接字与客户端本地信息结构体绑定 bind()

填充服务器本地信息结构体 sockaddr_un

进行通信 sendto( ) / recvfrom( )

2.2代码实现

服务器

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define ERRLOG(errmsg) do{\
        printf("%s:%s:%d --", __FILE__, __func__, __LINE__);\
        perror(errmsg);\
        exit(-1);\
    }while(0)

int main(int argc, const char *argv[]){
    if(2 != argc){
        printf("Usage : %s <filename>\n", argv[0]);
        return -1;
    }

    //创建用户数据报套接字
    int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if(-1 == sockfd){
        ERRLOG("socket error");
    }

    //填充服务器信息本地信息结构体
    struct sockaddr_un serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sun_family = AF_UNIX;
    strcpy(serveraddr.sun_path, argv[1]);

    socklen_t serveraddr_len = sizeof(serveraddr);

    //绑定
    if(-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){
        ERRLOG("bind error");
    }

    //定义结构体保存对方的信息
    struct sockaddr_un clientaddr;
    memset(&clientaddr, 0, sizeof(clientaddr));
    socklen_t clientaddr_len = sizeof(clientaddr);

    char buff[128] = {0};
    while(1){
        if(-1 == recvfrom(sockfd, buff, 128, 0, (struct sockaddr *)&clientaddr, &clientaddr_len)){
            ERRLOG("recv error");
        }
        printf("客户端[%s]发来数据[%s]\n", clientaddr.sun_path, buff);
        strcat(buff, "--hqyj");
        if(-1 == sendto(sockfd, buff, 128, 0, (struct sockaddr *)&clientaddr, clientaddr_len)){
            ERRLOG("send error");
        }
        memset(buff, 0, 128);
    }

    close(sockfd);

    return 0;
}

客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define ERRLOG(errmsg) do{\
        printf("%s:%s:%d --", __FILE__, __func__, __LINE__);\
        perror(errmsg);\
        exit(-1);\
    }while(0)

int main(int argc, const char *argv[]){
    if(3 != argc){
        printf("Usage : %s <server_filename> <client_filename>\n", argv[0]);
        return -1;
    }

    //创建用户数据报套接字
    int sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
    if(-1 == sockfd){
        ERRLOG("socket error");
    }

    //填充服务器本地信息结构体
    struct sockaddr_un serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sun_family = AF_UNIX;
    strcpy(serveraddr.sun_path, argv[1]);

    socklen_t serveraddr_len = sizeof(serveraddr);


    //定义客户端本地信息结构体
    struct sockaddr_un clientaddr;
    memset(&clientaddr, 0, sizeof(clientaddr));
    clientaddr.sun_family = AF_UNIX;
    strcpy(clientaddr.sun_path, argv[2]);
    socklen_t clientaddr_len = sizeof(clientaddr);

    //客户端需要绑定,否则服务器收不到客户端的文件名
    if(-1 == bind(sockfd, (struct sockaddr *)&clientaddr, clientaddr_len)){
        ERRLOG("bind error");
    }

    char buff[128] = {0};
    while(1){
        fgets(buff, 128, stdin);
        buff[strlen(buff)-1] = '\0';
        if(-1 == sendto(sockfd, buff, 128, 0, (struct sockaddr *)&serveraddr, serveraddr_len)){
            ERRLOG("send error");
        }
        //因为serveraddr没有变过 所以无需再保存了
        if(-1 == recvfrom(sockfd, buff, 128, 0, NULL, NULL)){
            ERRLOG("recv error");
        }
        printf("应答[%s]\n", buff);
        memset(buff, 0, 128);
    }

    close(sockfd);

    return 0;
}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 19:17:07  更:2022-07-20 19:20:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 20:27:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计