Socket的学习二

AF_UNIX实现本地通信:

1.Unix域的Socket通信及其优点

基于socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。
虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),
但是UNIX Domain Socket用于IPC 更有效率及可靠 :
不需要经过网络协议栈 不需要打包拆包、计算校验和、维护序号和应答等,可靠性更强 UNIX Domain Socket传输效率比通过loopback地址快将近一倍

2.预备知识 

需要了解:
socket通信基本概念 LINUX文件操作函数

LINUX文件操作函数:
read - 从文件描述符里读取数据
方法:ssize_t read(int fd, void *buf, size_t count);
参数:fd:文件描述符,对于本文而言是socket套接字
buf:缓冲区指针
count:预期读取的字节数
返回值:表示实际读到的字节数(字符串结束符 '\0’不算)
write - 从文件描述符里写入数据
函数定义:ssize_t write (int fd, const void * buf, size_t count);
 函数说明:write()会把参数buf所指的内存写入count个字节到参数放到所指的文件内。
 返回值:如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
附件说明:
1.write()函数返回值一般无0,只有当如下情况发生时才会返回0:
write(fp, p1+len, (strlen(p1)-len)中第三参数为0,
此时write()什么也不做,只返回0。man手册给出的write()返回值的说明如下:

      2.write()函数从buf写数据到fd中时,若buf中数据无法一次性读完,

        那么第二次读buf中数据时,其读位置指针(也就是第二个参数buf)

        不会自动移动,需要程序员编程控制,而不是简单的将buf首地址填入第二参数即可。

        如可按如下格式实现读位置移动:write(fp, p1+len, (strlen(p1)-len)。

        这样write第二次循环时变会从p1+len处写数据到fp, 之后的也由此类推,直至(strlen(p1)-len变为0。

      3.在write一次可以写的最大数据范围内(貌似是BUFSIZ ,8192),

        第三参数count大小最好为buf中数据的大小,以免出现错误。

       (经过笔者再次试验,write一次能够写入的并不只有8192这么多,笔者尝试一次写入81920000,结果也是可以,

         看来其一次最大写入数据并不是8192,但内核中确实有BUFSIZ这个参数,具体指什么还有待研究)

      例子:

         #include <string.h>
         #include <stdio.h>
         #include <fcntl.h>
         int main(){
            char *p1 = "This is a c test code";
            volatile int len = 0;
            int fp = open("/home/test.txt", O_RDWR|O_CREAT);
            for(;;) {
              int n;

              //if((n=write(fp, p1+len, 3)) == 0)
              if((n=write(fp, p1+len, (strlen(p1)-len)))== 0){      
                 //strlen(p1) = 21
                 printf("n = %d \n", n);
                 break;
              }
             len+=n;
          }
          return 0;
        }

        总结:此程序中的字符串"This is a c test code"有21个字符,经笔者亲自试验,若write时每次写3个字节,

             虽然可以将p1中数据写到fp中,但文件test.txt中会带有很多乱码。

              唯一正确的做法还是将第三参数设为(strlen(p1) - len,

              这样当write到p1末尾时(strlen(p1) - len将会变为0,

              此时符合附加说明(1)中所说情况,write返回0, write结束。

3.程序的功能及其实现 

程序的功能是实现客户端发送一个整型数据,服务端返回一个倒序的整型数据。
需要解决的问题:
  创建服务端和客户端
  数据处理
  数据处理部分函数实现:
int num_reverse(int num){
    int S=0,sum=0;
    while(num)
    {
        S=num%10; sum=10*sum+S; num = num / 10;
    }
  
    return sum;
}

服务端函数:
#include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/un.h> //define the sockaddr_un structure int num_reverse(int num); int main() { /* 断开之前的socket文件 */ unlink("server_socket"); /* 创建一个socket */ int server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un server_addr; server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, "server_socket"); /* 与本地文件进行绑定 */ bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); /* 监听 */ if(listen(server_sockfd, 5)<0); { perror("Listen failed"); } int client_sockfd; struct sockaddr_un client_addr; socklen_t len = sizeof(client_addr); while(1) { printf("server waiting:\n"); /* 接受一个客户端的链接 */ client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len); /*数据交换 */ read(client_sockfd, &num, 4); printf("get an integer from client: %d\n", num); num=num_reverse(num); write(client_sockfd, &num, 4); /* 关闭socket */ close(client_sockfd); } return 0; } int num_reverse(int num) { int S=0,sum=0; while(num) { S=num%10; sum=10*sum+S; num = num / 10; } return sum; }
客户端函数:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/un.h>

int main()
{
    /* 创建一个socket */
    int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    
    struct sockaddr_un address;
    address.sun_family = AF_UNIX;
    strcpy(address.sun_path, "server_socket");
    
    /*从键盘读取需要转置的整数*/
    int num;
    printf("Please enter the num to reverse:\n");

    /* 链接至服务端 */
    int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
    if(result == -1)
    {
        perror("connect failed: ");
        exit(1);
    }
    
    /* 数据处理 */
    write(sockfd, &num, 4);//一个int 4个字节
    read(sockfd, &num, 4);
    printf("get an integer from server: %d\n", num);
    
    /* 关闭socket */
    close(sockfd);
    
    return 0;
}  
makefile:
all:server.c client.c
    gcc -g -Wall -o server server.c
    gcc -g -Wall -o client client.c
clean:
    rm -rf *.o server client
验证结果:

 

 

 

学习来源:https://blog.csdn.net/weixin_39258979/article/details/80931464

                  //linux 读写操作

                 https://blog.csdn.net/boiled_water123/article/details/81951351

posted @ 2020-09-27 12:49  小窝蜗  阅读(196)  评论(0编辑  收藏  举报