C语言:详细讲解基于tcp和udp的两种本地通信方式

2023-11-04

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言:详细讲解基于tcp和udp的两种本地通信方式 的相关文章

  • NTP请求包

    我试图弄清楚我需要在 NTP 请求包中发送 客户端 什么才能从服务器检索 NTP 包 我正在 Cortex M3 Stellaris LM3S6965 上使用 LWIP 据我了解 我将收到 UDP 标头 然后收到具有不同时间戳的 NTP 协
  • 为什么我的 UDP 广播失败?

    我正在尝试发送 UDP 广播 但wireshark 没有报告任何流量 这是执行发送的代码片段 void SendBroadcast String ip 255 255 255 255 int port 30718 String messag
  • C++ 反序列化通过 UDP 从 C# 应用程序发送的对象

    我有一个申请c 它连接到另一个应用程序 编写为c 通过UDP 我更喜欢高性能的解决方案 因为我希望测量事件客户端 某些处理服务器端和客户端处理完成的响应之间的时间 本质上是 往返延迟 我有一个 C 对象 例如 public class Pa
  • HTTP 是否使用 UDP?

    这可能是一个愚蠢的问题 HTTP 是否使用过用户数据报协议 例如 如果使用 HTTP 传输 MP3 或视频 它内部是否使用 UDP 进行传输 From RFC 2616 http www ietf org rfc rfc2616 txt 通
  • 将 Docker 容器连接到网络接口/设备而不是 IP 地址

    经过仔细的研究 测试和摆弄 我只能找到通过从 IP 端口转发来将 Docker 容器连接到给定接口的方法 这可以通过添加来完成 p Host IP Host Port Container Port to a docker run命令 我有一
  • netty 4.x.x 中的 UDP 广播

    我们需要使用 Netty 4 0 0 二进制文件通过 UDP 通道广播对象 Pojo 在 Netty 4 0 0 中 它允许我们仅使用 DatagramPacket 类来发送 UDP 数据包 此类仅接受 ByteBuf 作为参数 还有其他方
  • 互联网上的 UDP 多播?

    我不确定如何最好地解决我的问题 我有一个在远程计算机上运行的服务 用于接收和处理 UDP 数据包 我希望该服务能够将这些数据包重新发送给任何需要它们的人 可能是任何人 通常是一台机器 但也可能更多 我认为 UDP 多播将是理想的 该服务可以
  • 对等网络应用程序的网络发现

    我希望有两个类 一个服务器类和一个客户端类 服务器类应该接收每个新客户端的 IP 地址和端口号并将它们存储在列表中 它应该为每个客户端提供已连接客户端及其 IP 地址的列表 然后 客户端可以使用 TCP 连接相互通信 问题是客户端不知道服务
  • 为什么我们可以将 sockaddr 转换为 sockaddr_in

    我明白为什么强制转换很有用sockaddr to sockaddr in 但我不明白这怎么可能 据我所知 它们的大小相同sockaddr in添加了sin zero使其大小相同 我想知道编译器如何知道从哪里获取信息sockaddr in如果
  • 在 macOS 10.12 上绑定到套接字时出现 NSPOSIXErrorDomain

    我正在玩CocoaAsyncSocket https github com robbiehanson CocoaAsyncSocket在 Swift 中绑定到 UDP 套接字并通过本地网络接收消息 我正在初始化一个套接字 并尝试绑定到一个端
  • Python UDP广播不发送

    我正在尝试从 Python 程序到两个 LabView 程序进行 UDP 广播 我似乎无法发送广播 我不确定我的套接字初始化错误在哪里 广播似乎足够简单 据我所知 其他电脑没有收到任何数据 另外 我将来还需要这个程序来接收来自其他电脑的数据
  • recvfrom() 中的 addrlen 字段有何用途?

    我在程序中使用 recvfrom 从我在 src addr 中指定的服务器获取 DGRAM 数据 但是 我不确定为什么需要初始化并传入addrlen 我读了手册页 但不太明白它的意思 如果src addr不为NULL 并且底层协议提供了源地
  • 为什么 UDP 服务器中只有一个套接字?

    我正在准备考试 发现了这个问题 典型的 UDP 服务器可以使用单个套接字来实现 解释一下为什么 对于 TCP 驱动的服务器 我发现创建了两个套接字 一个用于所有客户端访问服务器 另一个用于每个客户端的特定 套接字 用于服务器和客户端之间的进
  • C# 套接字数据报溢出

    我是 C 新手 我有一个关于udp套接字的小问题 我有一个聊天服务器 它接收特定结构的数据包 udp 数据报 为什么程序在套接字缓冲区已满时才接收数据 难道以后的一切就不应该失去吗 也许会出现数据包碎片 数据包结构 udp headers
  • SO_BINDTODEVICE Linux 套接字选项的问题

    我有一台带有两个网卡的电脑 一 eth0 用于 LAN 互联网 另一个用于与一个微控制器设备进行 UDP 通信 微控制器有一个 IP 192 168 7 2 和一个 MAC 地址 第二个电脑网络适配器 eth1 有 192 168 7 1
  • 用于实时传输协议的开源 .net C# 库

    net中有好的RTP开源库吗 我的目的是用于音频和视频同步问题并提高每秒帧数速率 我对 RTP 不太了解 但你可能想看看本文 http www codeproject com KB IP Using RTP in Multicasting
  • 无法从 run 方法中访问对象的属性(方法)! Java多线程

    我在 ServerConnectionManager 中有以下代码 public class ServerConnectionManager implements Runnable private DatagramPacket receiv
  • UDP SocketException - 通常只允许每个套接字地址使用一次

    尽管这里有很多非常相似的问题 但提供的答案都没有帮助我 这让我很难过 我有一个非常大的管理系统 我的任务是为其编写一些 UDP 数据包发送 接收 我已经编写了一个原型 一切都很好 所以我开始将我的代码合并到所述系统中 然而 我现在弹出了一个
  • Netty UDP 服务器中的线程未同时执行

    我正在分析的代码使用 Netty NioDatagramChannelFactory 创建 UDP 服务器 它创建一个线程池 ExecutorService threadPool Executors newCachedThreadPool
  • UNIX 域 STREAM 和 DATAGRAM 套接字之间的区别?

    这个问题是NOTSTREAM 类型和 DATAGRAM 类型 INTERNET 套接字之间的区别 我知道 STREAM 套接字使用 TCP 数据报套接字使用 UDP 以及所有 TCP UDP 内容 按顺序到达的数据包 ACK NACK 等

随机推荐

  • 初识Java

    Java之父 詹姆斯 高斯林 Write once Run anywhere jdk jre jvm的关系 jdk Java开发工具 jre Java运行环境 jvm Java虚拟机 xxx java程序的运行 首先javac xxx ja
  • 【Protobuf】pb中类型字段不匹配问题

    文章目录 背景 结论 原始数据 测试1 测试2 背景 客户端更新proto 新增message字段 探索新增字段的数据类型和标签对服务端反序列化数据的影响 结论 新增字段数据类型与服务端相同标签数据类型 不同 无法获取数据 但是不报错 相同
  • Request应用

    request getRequestDispatcher url 的url可以是相对路径也可以是绝对路径 getRequestDispatcher分成两种 可以用request调用 也可以用getServletContext 调用 不同的是
  • Apache Tomcat 官网下载(保姆级教程)

    目录 前言 一 环境说明 二 官网下载 1 进入官网 2 选择下载版本 3 进入版本页面 4 选择下载 总结 前言 Apache Tomcat 它是目前使用最广泛的Java应用服务器之一 我们在下载的时候千万不要去第三方网站 可以直接官网下
  • 前端下载二进制流pdf文件,下载成功,打开空白问题解决

    做pdf文件下载的时候 后端返回了二进制数据流 前端在发起请求时需要设置responseType arraybuffer 或者blob类型才可以 具体操作可以看我之前的文章 传送门 一开始对接的时候下载打开都是正常的 过后突然就不行了 能下
  • MySQL-----事务管理

    文章目录 前言 一 什么是事务 二 为什么会出现事务 三 事物的版本支持 四 事物的提交方式 五 事务常见的操作方式 六 事务隔离级别 如何理解隔离性1 隔离级别 查看与设置隔离性 读未提交 Read Uncommitted 读提交 Rea
  • SpringMVC工作原理

    文章搬运自 https www cnblogs com xiaoxi p 6164383 html SpringMVC工作原理 SpringMVC的工作原理图 SpringMVC流程 1 用户发送请求至前端控制器DispatcherServ
  • Android 13 - binder阅读(5)- 使用ServiceManager注册服务2

    上一篇笔记我们看到了binder transaction 这个方法很长 这一篇我们将把这个方法拆分开来看binder transaction做了什么 从而学习binder是如何跨进程通信的 1 binder transaction stat
  • ajax中load方法,jQuery中ajax的load()方法用法实例

    本文实例讲述了jQuery中ajax的load 方法用法 分享给大家供大家参考 具体分析如下 此函数jQuery中简单而功能强大的ajax方法 它可以从服务器加载内容 然后写入匹配元素 语法结构 selector load URL data
  • 将sql service数据库中的数据迁移到clickhourse中

    首先我们要根据sql server数据库的表在clickhourse中对应的建立表 CREATE TABLE IF NOT EXISTS default PosSalSheet SheetID String PosType Int8 Sta
  • 操作系统 3.2 进程概念

    单选题 共10题 下面关于进程的叙述 最不符合操作系统对进程的理解 A 进程是多程序环境中的完整的程序 B 进程可以由程序 数据和进程控制块描述 C 进程和程序是多对多的关系 D 进程是程序在一个数据集合上运行的过程 它是系统进行资源分配和
  • STM32 主从蓝牙模块配置

    前言 最近在调试小车的时候 突然想要用两个蓝牙进行单片机和电脑的交互 之前一直用的都是从机的蓝牙 这里因为需要双机通信 所以也就顺便查询了一些资料 了解一下主从蓝牙模块的使用 以及双机通信的一些使用 话不多说 开始 AT指令 蓝牙模块需要通
  • react强制组件刷新_如何强制刷新React子组件:简单方法

    react强制组件刷新 Note As of React 16 componentWillReceiveProps is deprecated meaning if you are using that version or higher
  • JS组件Bootstrap实现弹出框和提示框效果代码

    这篇文章主要介绍了JS组件Bootstrap实现弹出框和提示框效果代码 对弹出框和提示框感兴趣的小伙伴们可以参考一下 前言 对于Web开发人员 弹出框和提示框的使用肯定不会陌生 比如常见的表格新增和编辑功能 一般常见的主要有两种处理方式 行
  • Python研发工程师必备工具合集

    Python研发工程师必备工具合集 1 必备工具 2 常用网站 3 学习路线 4 必备技能 5 书籍推荐 6 进阶学习 一 必备工具 1 Sublime Text 2 Notepad 3 Visual Studio Code 4 Atom
  • 宝塔环境,后台上传图片不成功问题

    主要是宝塔开启了post攻击拦截导致的 关闭之后就可以了 或者选择性关闭规则 我的项目追踪请求返回内容 div 宝塔免费WAF提醒您 from data 请求异常 拒绝访问 如有误报请点击误报 div
  • 第十章 数据库恢复技术

    第十章 数据库恢复技术 10 1 事务的基本概念 事务 事务是用户定义的一个数据库操作序列 这些操作要么全做 要么全不做 是一个不可分割的工作单位 例 事务的特性 ACID特性 ACID properties 原子性 Atomicity 事
  • Jetbrains相关IDE下载历史版本

    进入 https www jetbrains com zh cn phpstorm download other html 点击相应的IDE 在连接最后添加 字符串 download other html 回车 跳转到当前IDE历史版本下载
  • python3.6 安装torch、torchvision

    python3 6安装torch torchvision 1 进入torch的官网的下载页面 选择一下参数信息 2 下载 whl 文件到本地 直接复制那个地址 3 把刚刚下载的两个文件 放到安装python安装文件夹里面去 比如 我是复制到
  • C语言:详细讲解基于tcp和udp的两种本地通信方式

    udp本地通信注意 客户端这边必须要绑定自己的客户端信息不然服务器就无法给客户端发送消息 原因是网络编程的时候客户端信息操作系统会自动分配 而本地通信并不会 本地通信的时候 服务器的那个套接字文件是用来标识服务器进程的 客户端得用两个套接字