本地实现的一个网络通信协议,采用主从架构,客户端发送报文给服务端,服务端收到后返回确认值。使用domain_socket的两组服务器端和客户端模拟全双工信道。然后将输入、数据发送、数据接受交给不同的线程来处理,以此实现事务分离。
Corporate with 西居原野
一、通信方式
-
全双工通信
通信双方均有一个client客户端和一个server服务端,分别用于发送和接收数据。在同一时间内,数据可以双向传输.
client
端键入数据,并存储在缓存区buffer
中;服务器端从buffer
中取出一段数据传输给server
端,并标记client
端的send
标识符;若server
端接收到client
传来的数据,则标记server
端的receive
标识符,否则传递传输错误信号给client
端,进行数据重传;标记server
端send
标识符,发送读取成功信号给client
端的receive
标识符,继续读取缓存区中的数据到send
中。 -
流量控制
本课设使用停止等待协议,通过
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值。
- ①设置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); } }
(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端初始化
- server端初始化
- 发送端键入数据后显示
- 接收端接收数据后显示
六、源代码
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
}