本地实现的一个网络通信协议,采用主从架构,客户端发送报文给服务端,服务端收到后返回确认值。使用domain_socket的两组服务器端和客户端模拟全双工信道。然后将输入、数据发送、数据接受交给不同的线程来处理,以此实现事务分离。

Corporate with 西居原野


一、通信方式

  1. 全双工通信

    通信双方均有一个client客户端和一个server服务端,分别用于发送和接收数据。在同一时间内,数据可以双向传输.

    client端键入数据,并存储在缓存区buffer中;服务器端从buffer中取出一段数据传输给server端,并标记client端的send标识符;若server端接收到client传来的数据,则标记server端的receive标识符,否则传递传输错误信号给client端,进行数据重传;标记serversend标识符,发送读取成功信号给client端的receive标识符,继续读取缓存区中的数据到send中。

    Alt text

  2. 流量控制

    本课设使用停止等待协议,通过Sleep()函数,停止等待键盘键入数据信息,并将数据以队列结构存储在缓冲区中。
    发送端每发送一条数据,接收端停止等待信道传输,接收端收到并返回收到确认后,发送端再从缓冲区中取出下一条数据进行发送;
    若接收端信息接收错误,就返回接收有误信息给发送端,发送端即进行数据超时重传。

二、客户端 Client

定义函数:

void* thread_scanf(void *arg);                  //输入线程子函数
void *sender(void *arg);                        //发送报文线程子函数
void *reserver(void *arg);                      //接收报文线程子函数
void combine_frame();                           //组帧_发送information
void show_frame();                              //显示发送的报文
int resolve_frame();                            //解析接收的报文
void combine_frame_domain();                    //组帧_开启和关闭
uint16_t crc16(unsigned char *addr, int num);   //crc校验函数

1. 宏定义

  • #define BUFFER_LEN 200 假设信道容量
  • #define STR_LEN 180 设置最大字符长度
  • #define TTL 2 设置的超时时间,如果超时没收到回送报文,则认为没送达
  • #define POLY 0x1021 设置的crc校验中的除数

2. 报文段

(1) 报文组成

flag addr_destin addr_local control infor crc flag
8位 8位 8位 8位 任意位 16位 8位
  • flag_define

    • 报文头尾标识符
    • 初始值:0000 1101B 或 0x0D
    • 长度:8位
  • addr_local

    • 发送端标识符
    • 初始值:0000 0000 或 0x00
    • 长度:8位
  • addr_destin

    • 接收端标识符
    • 初始值:0000 0001B 或 0x01
    • 长度:8位
  • control

    • 报文中用来实现各种功能的控制位
    • 初始值:无
    • 长度:8位
  • infor

    • 互传的数据
    • 初始值:无
    • 长度:任意
  • crc

    • 校验位
    • 初始值:无
    • 长度:16位

(2) control 标识符组成

标识符名称 open_request open_reply sender recever close_request close_reply
二进制 1100 0000B 1000 0000B 0000 0000B 0000 1111B 0001 0000B 0011 0000B
16进制 0xC0 0x80 0x00 0x0F 0x10 0x30
  • open_request
    • 打开请求
    • 协议约定:1100 0000 或 0xC0
  • open_reply
    • 打开回应
    • 协议约定:1000 0000 或 0x80
  • sender
    • 发送端
    • 协议约定:0000 0000 或 0x00
  • recever
    • 接收端
    • 协议约定:0000 1111 或 0x0f
  • close_request
    • 关闭请求
    • 协议约定:0001 0000 或 0x10
  • close_reply
    • 关闭回应
    • 协议约定:0011 0000 或 0x30

(3) 显示发送的报文

void show_frame(){
    unsigned char *head;
    head=&buf_sender[0];
    printf("---send---\n");                     //发送的报文
    printf("flag:\t0x%X\n",*head++);
    printf("addr_d:\t0x%X\n",*head++);
    printf("addr_l:\t0x%X\n",*head++);
    printf("ctl:\t0x%X\n",*head++);
    printf("infor:\t");
    while(*head!=flag_define){
        printf("%c",*head++);
    }
    printf("\n");
    printf("flag:\t0x%X\n",*head);
    printf("----------\n");
}

(4) 解析接收的报文

int resolve_frame(){

    unsigned char *head=&buf_reserver[0];

    if(*head!=flag_define){                     //判断flag是否出错
        printf("Flag error1\n");
        return 0;
    }

    printf("addr_d:\t0x%X\n",*++head);          //addr_destin
    if(*head!=addr_local){
        printf("I am not the destin\n");
        return 0;
    }

    printf("addr_l:\t0x%X\n",*++head);          //addr_local
    if(*head!=addr_destin){
        printf("This is not my destin\n");
        return 0;
    }

    printf("ctl:\t0x%X\n",*++head);             //control
    pthread_mutex_lock(&mutex);                 //上多进程锁
    if(*head==0x80)
        flag=3;
    if(*head==0x0f)
        flag=3;
    if(*head==0x30)
        flag=2;
    pthread_mutex_unlock(&mutex);               //解多进程锁

    crc[1]==*++head;                            //crc
    crc[2]==*++head;
    crc_buffer=crc16(crc_str,strlen(crc_str));
    if(*crc_buffer_1!=crc[1]||*crc_buffer_2!=crc[2]){
        return 0;
    }


    if(*++head!=flag_define){                   //判断flag是否出错
        printf("Flag error2\n");
        return 0;
    }

    return 1;                                   //解析成功,返回1;失败返回0
}

(5) CRC校验

  • 原理:
    • 将传输的数据当做一个位数很长(此处为16字节的数,将这个数除以另一个数,得到的余数作为校验数据附加到原数据后面。
  • 程序编写:
    • ①设置CRC寄存器,并给其赋值为“余数初始值”;
      ②将数据的第一个8-bit字符和CRC寄存器进行异或,并把结果存入CRC寄存器 ;
      ③CRC寄存器向右移一位,MSB补零,移出并检查LSB;
      ④如果LSB为0,重复第三步;若LSB为1,CRC寄存器与0x31相异或。
      ⑤重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕;
      ⑥重复第2到第5步直到所有数据全部处理完成;
      ⑦最终CRC寄存器的内容与“结果异或之”进行或非操作后即为CRC值。
uint16_t crc16(unsigned char *addr, int num){  
    uint16_t crc=0xFFFF;                //初始值
    int i;  
    for (; num > 0; num--)              //通过寄存器中字节数
    {  
        crc = crc ^ (*addr++ << 8);     //数据的第一个8-bit字符和CRC寄存器进行异或
        for (i = 0; i < 8; i++)         //循环 8 bits
        {  
            if (crc & 0x8000)
                crc = (crc << 1) ^ POLY;  //多项式移位、异或操作
            else
                crc <<= 1;               //仅移位操作
        }                   
        crc &= 0xFFFF;                  //保证CRC为16位值
    }        
    return(crc);                        //返回更新后的CRC值  
} 

三. 创建通信

1. 参数设置

  • int flag=0;

    • 用来判断进入建立连接、拆除连接、通信哪个过程的标识
  • pthread_mutex_t mutex;

    • 多线程锁,由于flag标志符是多个线程共享的变量,多线程锁保证当一个线程在修改flag值时,其他线程不会读取和修改flag值
  • struct sockaddr_un un_sender,un_reserver;

    • domain_socket,实现一个全双工信道
  • unsigned char buf_sender[BUFFER_LEN],buf_reserver[BUFFER_LEN];

    • 发送报文和接收的缓存
  • queue <SCAN> buffer;

    • 输入的数据入队push,然后根据发送程序自动出队发送pop

2. 线程初始化

    pthread_t scanner_thread,sender_thread,reserver_thread;
    pthread_mutex_init( &mutex, NULL);  //包含在头文件 pthread.h 中
  • pthread_mutex_init( &mutex, NULL)
    • 作用:初始化 mutex 多进程锁

3.组帧

(1)开启和关闭

void combine_frame_domain(){
    memset(&buf_sender, 0, sizeof(buf_sender));
    buf_sender[0]=flag_define;  //第一位:flag[8]
    buf_sender[1]=addr_destin;  //第二位:addr_destin
    buf_sender[2]=addr_local;   //第三位:addr_local

    if(flag==0)
        control=0xc0;   //open_request 打开请求
    if(flag==2)
        control=0x10;   //close_request 关闭请求
    buf_sender[3]=control;      //第四位:control位
    buf_sender[4]=crc[1];       //第五位
    buf_sender[5]=crc[2];
                                //第六位:information NULL
    buf_sender[6]=flag_define;  //最后:flag
}

(2)发送information

void combine_frame(){
    int i;
    buf_sender[0]=flag_define;  //flag[8]
    buf_sender[1]=addr_destin;  //addr_destin
    buf_sender[2]=addr_local;   //addr_local

    control=0x00;
    buf_sender[3]=control;      //control为0时,发送信息

    char *ch=buffer.front().data;//information
    for( i=4;i<(strlen(buffer.front().data)+4);i++){
        buf_sender[i]=*ch;
        ch++;
    }
    buf_sender[i]=crc[1];       
    buf_sender[i+1]=crc[2];
    buf_sender[i+2]=flag_define;    //flag[8]
    buffer.pop();
}

4.三线程并行

pthread_create(&scanner_thread,NULL,thread_scanf,NULL);//负责接收终端输入
pthread_create(&sender_thread,NULL,sender,NULL);       //负责发送报文
pthread_create(&reserver_thread,NULL,reserver,NULL);   //负责接收报文

(1)接收终端输入

pthread_create( &scanner_thread, NULL, thread_scanf, NULL );

  • 输入线程子函数 thread_scanf ( ):
      void* thread_scanf(void *arg){
          SCAN temp;
          sleep(5);                                //等待系统初始化再输入
          while(1){
              printf("Wait inputing....\n");
              scanf("%s",temp.data);
              buffer.push(temp);
          }
      }

(2)发送报文

pthread_create( &sender_thread, NULL, sender, NULL );

  • 发送报文线程子函数 sender

    • 考虑通信出错情况
      if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
          perror("socket error");
          exit(1);
      }
          if (connect(fd, (struct sockaddr *)&un_sender, len) < 0){
          perror("connect error");
          exit(1);
      }
    • 建立连接 ( flag=0 )
          if(flag==0){      
               combine_frame_domain();    //组帧发送
               if(write(fd,buf_sender,sizeof(buf_sender))<0){
                  perror("write error");
                  exit(0);
               }
    
               pthread_mutex_lock(&mutex); //上多进程锁(避免flag被其他进程修改)
               flag=1;                     //flag的中间状态
               pthread_mutex_unlock(&mutex);//解多进程锁
               printf("Send open_request frame...\n");
               sleep(TTL);                  //超时重传
    
               while(flag==1){              //当为中间状态时,建立连接失败
                  printf("Time out,send open_request frame again\n");
                  if(write(fd,buf_sender,sizeof(buf_sender))<0){
                      perror("write error");
                      exit(0);
                  }
                  sleep(TTL);                //超时重传
               }
          }
    • 拆除连接 ( flag=2 )
          if(flag==2){
              combine_frame_domain();         //组帧发送
              if(write(fd,buf_sender,sizeof(buf_sender))<0){
                  perror("write error");
                  exit(0);
              }
    
              pthread_mutex_lock(&mutex);     //上多进程锁
              flag=1;
              pthread_mutex_unlock(&mutex);   //解多进程锁
              printf("Send close_request frame...\n");
              sleep(TTL);                     //超时重传
    
              while(flag==1){                 //当flag处于中间状态,拆除连接失败
                  printf("Time out,send close_request frame again\n");
                  if(write(fd,buf_sender,sizeof(buf_sender))<0){
                      perror("write error");
                      exit(0);
                  }
                  sleep(TTL);
              }
          }
    • 发送消息( flag=3 )
          if(flag==3&&buffer.empty()!=true){
              combine_frame();                //组帧发送
              if(write(fd,buf_sender,sizeof(buf_sender))<0){
                  perror("write error");
                  exit(0);
              }
    
              pthread_mutex_lock(&mutex);     //上进程锁
              flag=1;
              pthread_mutex_unlock(&mutex);   //解进程锁
              show_frame();
    
              sleep(TTL);                     //超时重传
              while(flag==1){
                  printf("Time out,let me send again...\n");
                  if(write(fd,buf_sender,sizeof(buf_sender))<0){
                      perror("write error");
                      exit(0);
                  }
                  sleep(TTL);
              }
          }

Alt text

(3)接收报文

pthread_create( &reserver_thread, NULL, reserver, NULL );

  • 接收报文线程子函数 reserver

    • 接收出错

        if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ 
            perror("socket error");     //socket
            exit(1);
        }
      
        if (bind(fd, (struct sockaddr*)&un_reserver, len) < 0){
            perror("bind error");       //bind
            exit(1);
        }
      
        if (listen(fd, QLEN) < 0){      //listen
            perror("listen error");
            exit(1);
        }
      
        if ((clifd = accept(fd, (struct sockaddr*)&un_reserver, (unsigned *)&len)) < 0){       
            perror("accept error");     //accept
            exit(1);
        }
    • 接收正常,显示接收信息

        while(1)
        {
            memset(&buf_reserver, 0, sizeof(buf_reserver));
      
            if(read(clifd, buf_reserver, BUFFER_LEN)==0)
                break;
      
            printf("***receive***\n");
            resolve_frame();              //解析报文
            printf("*************\n");
        }

四、服务端 Server

与客户机 Client 区别:不做超时重传。

定义函数:

void* reserver(void *arg);                      //接受报文线程子函数                 
void* sender(void *arg);                        //发送报文线程子函数
int resolve_frame();                            //解析接受的报文
void show_frame();                              //显示发送的报文
void combine_frame_reply();                     //组帧_返回接收信息
uint16_t crc16(unsigned char *addr, int num);   //crc校验函数

1. 报文

(1)报文组成同客户端 Client

falg addr_destin addr_local control infor crc flag
8位 8位 8位 8位 任意位 16位 8位

(2)control标识符同客户端 Client

标识符名称 open_request open_reply sender recever close_request close_reply
二进制 1100 0000B 1000 0000B 0000 0000B 0000 1111B 0001 0000B 0011 0000B
16进制 0xC0 0x80 0x00 0x0F 0x10 0x30

2.组帧

根据从Client端接收来的内容,修改报文相关信息

void combine_frame_reply(){

    memset(&buf_sender, 0, sizeof(buf_sender));
    buf_sender[0]=flag_define;          //flag[8]
    buf_sender[1]=addr_destin;          //addr_destin
    buf_sender[2]=addr_local;           //addr_local

    if(flag==1)
        control=0x80;                   //open_reply
    if(flag==2)
        control=0x0f;                   //receive
    if(flag==3)
        control=0x30;                   //close_reply
    buf_sender[3]=control;              //control
    buf_sender[4]=crc[1];               //crc
    buf_sender[5]=crc[2];
                                        //information NULL
    buf_sender[6]=flag_define;          //flag
}

3. 二线程并行

pthread_create(&thread_reserver,NULL,reserver,NULL);    //负责接收报文
pthread_create(&thread_sender,NULL,sender,NULL);        //负责发送报文

(1) 接收报文

接收函数 reserver 同客户端 Client

(2) 发送报文

发送报文函数与客户端 Client 的发送报文不同处:

  • 无需建立连接(flag=0)、拆除连接(flag=2)、发送消息(flag=3)
  • 无需设置超时重传(超时时间TTL)
void* sender(void *arg){
    sleep(5);
    int fd, serfd,len;
    memset(&un_sender, 0, sizeof(un_sender));
    un_sender.sun_family = AF_UNIX;
    strcpy(un_sender.sun_path, (char*)"foo1.socket");

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
        perror("socket error");
        exit(1);
    }

    len = offsetof(struct sockaddr_un, sun_path) + strlen((char*)"foo1.socket");

    if (connect(fd, (struct sockaddr *)&un_sender, len) < 0)
    {
        perror("connect error");
        exit(1);
    }
    char temp[]="hello";

    while(1){                       //与Client的发送报文仅此处不同

        if(if_send==1){
                                    //回传消息,不做客户机不做超时重传
            memset(&buf_sender, 0, sizeof(buf_sender));
            combine_frame_reply();
            if(write(fd,buf_sender,sizeof(buf_sender))<0){
                perror("write error");
                exit(0);
            }
            show_frame();
            if_send=0;
        }

    }
}

五、运行显示

  • client端初始化
    Alt text
  • server端初始化
    Alt text
  • 发送端键入数据后显示
    Alt text
  • 接收端接收数据后显示
    Alt text

六、源代码

1. client.cpp

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/un.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace std;

#define BUFFER_LEN 200  //假设信道容量
#define QLEN 10
#define STR_LEN 180 //最大字符长度
#define TTL 2   //设置的超时时间time to live  如果超时没收到回送报文,则认为没送达

int flag_define=0x0D;   //Flag   0000 1101  0x0D 
int addr_local=0x00;    //0000 0000   
int addr_destin=0x01;
pthread_mutex_t mutex; //多线程-锁

/*define control
    open_request  1100 0000 0xC0
    open_reply    1000 0000 0x80
    sender        0000 0000 0x00
    recever       0000 1111 0x0f
    close_request 0001 0000 0x10
    close_reply   0011 0000 0x30
 */
unsigned char control;  //报文中用来实现各种功能的控制位
int flag=0; //用来判断进入建立连接、拆除连接、通信哪个过程的标识

struct SCAN{
    char data[STR_LEN];
};

struct sockaddr_un un_sender,un_reserver;   //  domain_socket 实现一个全双工信道
unsigned char buf_sender[BUFFER_LEN],buf_reserver[BUFFER_LEN];//发送报文和接收的缓存
queue <SCAN> buffer;    //输入的数据入队push,然后根据发送程序自动出队发送pop


void* thread_scanf(void *arg);
void *sender(void *arg);
void *reserver(void *arg);
void combine_frame();
void show_frame();
int resolve_frame();
void combine_frame_domain();


int main(){
    //多线程初始化
    pthread_t scanner_thread,sender_thread,reserver_thread;
    pthread_mutex_init(&mutex,NULL);//互斥量

    //同时开启三个线程,分别负责接受终端的输入、发送报文、接受报文
    pthread_create(&scanner_thread,NULL,thread_scanf,NULL);
    pthread_create(&sender_thread,NULL,sender,NULL);
    pthread_create(&reserver_thread,NULL,reserver,NULL);

    pthread_join(scanner_thread,NULL);
    pthread_join(sender_thread,NULL);
    pthread_join(reserver_thread,NULL);

    pthread_mutex_destroy(&mutex);
}

//输入线程子函数
void* thread_scanf(void *arg){
    SCAN temp;
    sleep(5);   //  等待系统初始化再输入
    while(1){
        printf("Wait inputing....\n");
        scanf("%s",temp.data);
        buffer.push(temp);
    }
}

//发送报文线程子函数
void *sender(void *arg){
    int fd, serfd,len;
    memset(&un_sender, 0, sizeof(un_sender));
    un_sender.sun_family = AF_UNIX;
    strcpy(un_sender.sun_path, (char*)"foo.socket");


    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
        perror("socket error");
        exit(1);
    }

    len = offsetof(struct sockaddr_un, sun_path) + strlen((char*)"foo.socket");

    if (connect(fd, (struct sockaddr *)&un_sender, len) < 0)
    {
        perror("connect error");
        exit(1);
    }

    while(1){
        sleep(1);//等待1s模拟信道传输时间
        //建立连接
        if(flag==0){
            // printf("->flag0\n");
            combine_frame_domain();//组帧发送
            if(write(fd,buf_sender,sizeof(buf_sender))<0){
                perror("write error");
                exit(0);
            }
            pthread_mutex_lock(&mutex);//上锁
            flag=1;
            pthread_mutex_unlock(&mutex);//解锁
            printf("Send open_request frame...\n");
            sleep(TTL);//超时重传
            while(flag==1){
                // printf("->hello\n");
                printf("Time out,send open_request frame again\n");
                if(write(fd,buf_sender,sizeof(buf_sender))<0){
                    perror("write error");
                    exit(0);
                }
                sleep(TTL);
            }
        }

        //拆除连接
        if(flag==2){
            // printf("->flag2\n");
            combine_frame_domain();
            if(write(fd,buf_sender,sizeof(buf_sender))<0){
                perror("write error");
                exit(0);
            }
            pthread_mutex_lock(&mutex);
            flag=1;
            pthread_mutex_unlock(&mutex);
            printf("Send close_request frame...\n");
            sleep(TTL);
            while(flag==1){
                printf("Time out,send close_request frame again\n");
                if(write(fd,buf_sender,sizeof(buf_sender))<0){
                    perror("write error");
                    exit(0);
                }
                sleep(TTL);
            }
        }

        //发送消息
        if(flag==3&&buffer.empty()!=true){
            // printf("->flag3\n");
            //组帧发送
            combine_frame();
            if(write(fd,buf_sender,sizeof(buf_sender))<0){
                perror("write error");
                exit(0);
            }
            pthread_mutex_lock(&mutex);
            flag=1;
            pthread_mutex_unlock(&mutex);
            show_frame();

            //超时重传
            sleep(TTL);
            while(flag==1){
                printf("Time out,let me send again...\n");
                if(write(fd,buf_sender,sizeof(buf_sender))<0){
                    perror("write error");
                    exit(0);
                }
                sleep(TTL);
            }
        }

    }

    close(fd);
}

//组帧_开启和关闭
void combine_frame_domain(){
    memset(&buf_sender, 0, sizeof(buf_sender));
    buf_sender[0]=flag_define;  //flag[8]
    buf_sender[1]=addr_destin;  //addr_destin
    buf_sender[2]=addr_local;   //addr_local

    if(flag==0)
        control=0xc0;   //open_request
    if(flag==2)
        control=0x10;   //close_request
    buf_sender[3]=control;  //control

                            //information NULL
    buf_sender[4]=flag_define;  //flag
}

//组帧_发送information
void combine_frame(){
    int i;
    buf_sender[0]=flag_define;  //flag[8]
    buf_sender[1]=addr_destin;  //addr_destin
    buf_sender[2]=addr_local;   //addr_local
    control=0x00;
    buf_sender[3]=control;  //control
    char *ch=buffer.front().data;   //information
    for( i=4;i<(strlen(buffer.front().data)+4);i++){
        buf_sender[i]=*ch;
        // cout<<*ch;
        // cout<<buf_sender[i];
        ch++;
    }
    buf_sender[i]=flag_define;  //flag[8]
    buffer.pop();
}

//显示发送的报文
void show_frame(){
    unsigned char *head;
    head=&buf_sender[0];
    printf("---send---\n");
    printf("flag:\t0x%X\n",*head++);
    printf("addr_d:\t0x%X\n",*head++);
    printf("addr_l:\t0x%X\n",*head++);
    printf("ctl:\t0x%X\n",*head++);
    printf("infor:\t");
    while(*head!=flag_define){
        printf("%c",*head++);
    }
    printf("\n");
    printf("flag:\t0x%X\n",*head);
    printf("----------\n");
}

//接受报文线程子函数
void *reserver(void *arg){
    int     clifd, fd, len;
    memset(&un_reserver, 0, sizeof(un_reserver)); //清空un
    un_reserver.sun_family = AF_UNIX;    
    strcpy(un_reserver.sun_path, "foo1.socket");
    unlink(un_reserver.sun_path);

    if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
        perror("socket error");
        exit(1);
    }

    len = offsetof(struct sockaddr_un, sun_path) + strlen(un_reserver.sun_path);

    //bind
    if (bind(fd, (struct sockaddr*)&un_reserver, len) < 0){
        perror("bind error");
        exit(1);
    }

    printf("UNIX domain socket bound\n");

    memset(&buf_reserver, 0, sizeof(buf_reserver));

    //listen
    if (listen(fd, QLEN) < 0){
        perror("listen error");
        exit(1);
    }

    //accept
    if ((clifd = accept(fd, (struct sockaddr*)&un_reserver, (unsigned *)&len)) < 0)
    {
        perror("accept error");
        exit(1);
    }

    while(1)
    {
        memset(&buf_reserver, 0, sizeof(buf_reserver));
        if(read(clifd, buf_reserver, BUFFER_LEN)==0)
            break;
        printf("***receive***\n");
        resolve_frame();
        printf("*************\n");
    }

    unlink(un_reserver.sun_path);
}

//解析接受的报文
int resolve_frame(){

    unsigned char *head=&buf_reserver[0];
    //flag
    if(*head!=flag_define){
        printf("Flag error1\n");
        return 0;
    }
    //addr_destin
    printf("addr_d:\t0x%X\n",*++head);
    if(*head!=addr_local){
        printf("I am not the destin\n");
        return 0;
    }
    //addr_local
    printf("addr_l:\t0x%X\n",*++head);
    if(*head!=addr_destin){
        printf("This is not my destin\n");
        return 0;
    }
    //control
    printf("ctl:\t0x%X\n",*++head);
    pthread_mutex_lock(&mutex);
    if(*head==0x80)
        flag=3;
    if(*head==0x0f)
        flag=3;
    if(*head==0x30)
        flag=2;
    pthread_mutex_unlock(&mutex);
    //flag
    // printf("flag:0x%X\n",*head);
    if(*++head!=flag_define){
        printf("Flag error2\n");
        return 0;
    }
    return 1;
}

2. server.cpp

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;


#define BUFFER_LEN 200
#define QLEN 10

int flag_define=0x0D;
int addr_local=0x01;    //0000 0001
int addr_destin=0x00;
int flag;
int if_send=0;

unsigned char control;  //open_request  1100 0000 0xC0
                //open_reply    1000 0000 0x80
                //sender        0000 0000 0x00
                //recever       0000 1111 0x0f
                //close_request 0001 0000 0x10
                //close_reply   0011 0000 0x30



unsigned char   buf_reserver[BUFFER_LEN],buf_sender[BUFFER_LEN];
struct  sockaddr_un un_reserver,un_sender;


void* reserver(void *arg);
void* sender(void *arg);
int resolve_frame();
void show_frame();
void combine_frame_reply();


int main(){
    pthread_t thread_reserver,thread_sender;

    pthread_create(&thread_reserver,NULL,reserver,NULL);
    pthread_create(&thread_sender,NULL,sender,NULL);

    pthread_join(thread_reserver,NULL);
    pthread_join(thread_sender,NULL);
}

void* reserver(void *arg){
    int     clifd, fd, len;
    memset(&un_reserver, 0, sizeof(un_reserver)); 
    un_reserver.sun_family = AF_UNIX;    
    strcpy(un_reserver.sun_path, "foo.socket");
    unlink(un_reserver.sun_path);

    if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
        perror("socket error");
        exit(1);
    }

    len = offsetof(struct sockaddr_un, sun_path) + strlen(un_reserver.sun_path);

    //bind
    if (bind(fd, (struct sockaddr*)&un_reserver, len) < 0){
        perror("bind error");
        exit(1);
    }

    printf("UNIX domain socket bound\n");

    memset(&buf_reserver, 0, sizeof(buf_reserver));

    //listen
    if (listen(fd, QLEN) < 0){
        perror("listen error");
        exit(1);
    }

    //accept
    if ((clifd = accept(fd, (struct sockaddr*)&un_reserver, (unsigned *)&len)) < 0)
    {
        perror("accept error");
        exit(1);
    }

    while(1)
    {

        memset(&buf_reserver, '\0', sizeof(buf_reserver));
        if(read(clifd, buf_reserver, BUFFER_LEN)==0)
            break;

        cout<<"***receive***"<<endl;
        if(resolve_frame()==0){
            cout<<"This frame is invalid"<<endl;
        }
        if_send=1;
        cout<<"*************"<<endl;

    }

    unlink(un_reserver.sun_path);
}

int resolve_frame(){

    unsigned char *head=&buf_reserver[0];
    //flag
    // printf("flag:0x%X\n",*head);
    if(*head!=flag_define){
        printf("Flag error1\n");
        return 0;
    }
    //addr_destin
    printf("addr_d:\t0x%X\n",*++head);
    if(*head!=addr_local){
        printf("I am not the destin\n");
        return 0;
    }
    //addr_local
    printf("addr_l:\t0x%X\n",*++head);
    if(*head!=addr_destin){
        printf("This is not my destin\n");
        return 0;
    }
    //control
    printf("ctl:\t0x%X\n",*++head);
    if(*head==0xc0)
        flag=1;
    if(*head==0x00)
        flag=2;
    if(*head==0x10)
        flag=3;
    //information
    printf("infor:\t");
    while(*++head!=flag_define){
        printf("%c",*head);
        if(*head=='\0'){
            return 0;
        }
    }
    printf("\n");
    //flag
    // printf("flag:0x%X\n",*head);
    if(*head!=flag_define){
        printf("Flag error2\n");
        return 0;
    }
    return 1;
}

void* sender(void *arg){
    sleep(5);
    int fd, serfd,len;
    memset(&un_sender, 0, sizeof(un_sender));
    un_sender.sun_family = AF_UNIX;
    strcpy(un_sender.sun_path, (char*)"foo1.socket");

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
        perror("socket error");
        exit(1);
    }

    len = offsetof(struct sockaddr_un, sun_path) + strlen((char*)"foo1.socket");

    if (connect(fd, (struct sockaddr *)&un_sender, len) < 0)
    {
        perror("connect error");
        exit(1);
    }
    char temp[]="hello";

    while(1){

        if(if_send==1){
            //回传消息,不做客户机不做超时重传
            memset(&buf_sender, 0, sizeof(buf_sender));
            combine_frame_reply();
            if(write(fd,buf_sender,sizeof(buf_sender))<0){
                perror("write error");
                exit(0);
            }
            show_frame();
            if_send=0;
        }

    }
}

void show_frame(){
    unsigned char *head;
    head=&buf_sender[0];
    printf("---send---\n");
    printf("flag:\t0x%X\n",*head++);
    printf("addr_d:\t0x%X\n",*head++);
    printf("addr_l:\t0x%X\n",*head++);
    printf("ctl:\t0x%X\n",*head++);
    printf("flag:\t0x%X\n",*head);
    printf("----------\n");
}

void combine_frame_reply(){

    memset(&buf_sender, 0, sizeof(buf_sender));
    buf_sender[0]=flag_define;  //flag[8]
    buf_sender[1]=addr_destin;  //addr_destin
    buf_sender[2]=addr_local;   //addr_local

    if(flag==1)
        control=0x80;   //open_reply
    if(flag==2)
        control=0x0f;   //receive
    if(flag==3)
        control=0x30;   //close_reply
    buf_sender[3]=control;  //control

                            //information NULL
    buf_sender[4]=flag_define;  //flag
}
Last modification:May 31st, 2020 at 10:00 pm