c++ socket send file_linux进程间通信---本地socket套接字(一)---一个server对应一个client...

先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题

4cbc30b07a9042a3a29205b4eb54b7d5.png

一 what
socket套接字也是一种文件格式,和管道文件一样,它是一种伪文件,存在于内核的缓冲区中,大小不变,一直是0。
套接字一定是成对出现的,有server套接字,就一定有client套接字,它是一种全双工通信方式,分别有读写缓冲区
通信框图,也称为cs架构如下

cs架构   

1.1 和套接字相关的几个地址结构体

struct sockaddr用来描述ipv4地址协议

f9e0f74f93b3a119dfc065d0d72f506d.png

1.2 和地址转换相关的几个函数

ip地址转换函数
inet_pton    192.168.1.24 --------------> 网络字节序
/* 
 * 参数 af,网络ip地址的版本,ipv4或ipv6
 *      src 192.168.1.24
 *      dst 网络字节序
 */
int inet_pton(int af, const char *src, void *dst);

inet_ntop    网络字节序 --------------> 点分十进制
/* 
 * 参数 af,网络ip地址的版本,ipv4或ipv6
 *      src 网络字节序
 *      dst 192.168.1.24
 *      size 字符串dst长度
 */
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

二 why
为什么需要套接字呢?它的目的是实现进程间通信,既可以实现同一个linux内核(同一台设备)进程间通信;又可以实现不同的linux内核(不同设备)进程间通信,比如我们浏览网页的过程其实就是一个socket通信模型。

三 how
本地套接字用于实现本机进程间通信,有tcp和udp类似两种,我们以类似tcp方式举例。

75765c19bbcf6ea1124d9075e5d78d94.png

3.1 server端的流程

1. 创建socket
    int ifd = socket(AF_LOCAL, sock_stream, 0);   //AF_UNIX也可以,AF_INET是指网络套接字
2. 绑定 struct sockaddr_un
    struct sockaddr_un serv;
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.socket");   //server.socket此时还不存在的,它什么时候会存在呢
    bind(ifd, (struct sockaddr *)&serv, sizeof(serv)); //绑定成功,server.socket这个文件就会被创建
3. 设置监听
    listen()
4. 等待接收连接请求
    struct sockaddr_un client;
    int len = sizeof(client);
    int cfd = accept(ifd, &client, &len);
5. 通信
    send     //发送数据
    recv     //接收数据
6. 断开连接

代码如下

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

int main(int argc, char *argv[])
{
    int lfd ,ret, cfd;
    struct sockaddr_un serv, client;
    socklen_t len = sizeof(client);
    char buf[1024] = {0};
    int recvlen;

    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");

    //绑定
    ret = bind(lfd, (struct sockaddr *)&serv, sizeof(serv));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //设置监听,设置能够同时和服务端连接的客户端数量
    ret = listen(lfd, 36);
    if (ret == -1) {
        perror("listen error");
        return -1;
    }

    //等待客户端连接
    cfd = accept(lfd, (struct sockaddr *)&client, &len);
    if (cfd == -1) {
        perror("accept error");
        return -1;
    }
    printf("=====client bind file:%sn", client.sun_path);
    
    while (1) {
        recvlen = recv(cfd, buf, sizeof(buf), 0);
        if (recvlen == -1) {
            perror("recv error");
            return -1;
        } else if (recvlen == 0) {
            printf("client disconnet...n");
            close(cfd);
            break;
        } else {
            printf("recv buf %sn", buf);
            send(cfd, buf, recvlen, 0);
        }
    }
    
    close(cfd);
    close(lfd);
    return 0;
}

3.2 client端的流程

1. 创建socket
    int fd = socket(AF_LOCAL, sock_stream, 0);   //AF_UNIX也可以,AF_INET是指网络套接字
2. 绑定套接字文件
    struct sockaddr_un client;
    client.sun_family = AF_LOCAL;
    strcpy(client.sun_path, "client.socket");   //client.socket此时还不存在的,它什么时候会存在呢
    bind(ifd, (struct sockaddr *)&client, len); //绑定成功,server.socket这个文件就会被创建
3. 连接服务器
    struct sockaddr_un serv;
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.socket");   //server.socket此时还不存在的,它什么时候会存在呢
    connect(fd, &serv, sizeof(serv))
4. 通信
    recv
    send
5. 关闭
    close

代码如下

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

int main(int argc, char *argv[])
{
    int lfd ,ret;
    struct sockaddr_un serv, client;
    socklen_t len = sizeof(client);
    char buf[1024] = {0};
    int recvlen;

    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }

    //给客户端绑定一个套接字文件
    client.sun_family = AF_LOCAL;
    strcpy(client.sun_path, "client.sock");
    ret = bind(lfd, (struct sockaddr *)&client, sizeof(client));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");
    //连接
    connect(lfd, (struct sockaddr *)&serv, sizeof(serv));

    while (1) {
        fgets(buf, sizeof(buf), stdin);
        send(lfd, buf, strlen(buf)+1, 0);

        recv(lfd, buf, sizeof(buf), 0);
        printf("recv buf %sn", buf);
    }

    close(lfd);
    return 0;
}

四 test4.1 编译运行

分别编译server.c和client.c,先运行./server,我们发现在当前目录下创建了一个serve.sock的套接字文件,文件类型是“s”,如下:

c621c6b738cdbbe914e1910fe2ae2f51.png

然后运行./client,同样发现创建了一个套接字文件client.sock,然后在client输入信息,就会在server端接收到信息了。

4.2 bug
我们会遇到一个问题,当我们停止./server或者./client,在运行./server或者./client,会发现一个错误提示:

b19da80ba7cf7f84548bcbd6e57c3b56.png

这是因为套接字文件已经存在,不能再bind了,我们需要修改源程序,在bind之前,加上unlink,就是说如果套接字文件存在,需要先删除套接字文件。

server代码修改如下

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

int main(int argc, char *argv[])
{
    int lfd ,ret, cfd;
    struct sockaddr_un serv, client;
    socklen_t len = sizeof(client);
    char buf[1024] = {0};
    int recvlen;

    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }
    
    //如果套接字文件存在,存删除套接字文件
    unlink("server.sock");

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");

    //绑定
    ret = bind(lfd, (struct sockaddr *)&serv, sizeof(serv));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //监听
    ret = listen(lfd, 36);
    if (ret == -1) {
        perror("listen error");
        return -1;
    }

    //等待客户端连接
    cfd = accept(lfd, (struct sockaddr *)&client, &len);
    if (cfd == -1) {
        perror("accept error");
        return -1;
    }
    printf("=====client bind file:%sn", client.sun_path);
    
    while (1) {
        recvlen = recv(cfd, buf, sizeof(buf), 0);
        if (recvlen == -1) {
            perror("recv error");
            return -1;
        } else if (recvlen == 0) {
            printf("client disconnet...n");
            close(cfd);
            break;
        } else {
            printf("recv buf %sn", buf);
            send(cfd, buf, recvlen, 0);
        }
    }
    
    close(cfd);
    close(lfd);
    return 0;
}

client代码如下:

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

int main(int argc, char *argv[])
{
    int lfd ,ret;
    struct sockaddr_un serv, client;
    socklen_t len = sizeof(client);
    char buf[1024] = {0};
    int recvlen;

    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }

    //如果套接字文件存在,存删除套接字文件
    unlink("client.sock");

    //给客户端绑定一个套接字文件
    client.sun_family = AF_LOCAL;
    strcpy(client.sun_path, "client.sock");
    ret = bind(lfd, (struct sockaddr *)&client, sizeof(client));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");
    //连接
    connect(lfd, (struct sockaddr *)&serv, sizeof(serv));

    while (1) {
        fgets(buf, sizeof(buf), stdin);
        send(lfd, buf, strlen(buf)+1, 0);

        recv(lfd, buf, sizeof(buf), 0);
        printf("recv buf %sn", buf);
    }

    close(lfd);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值