初步的界面如下:
为了实现不同的窗口、不同进程弈五子棋对弈,就需要在不同进程间的进行通信,我们采用linux底层的命名管道进行通信。
首先我们要进行管道通信头文件的包含、传输数据的结构定义、数据通信操作的函数定义(代码如下):
1 #ifndef MESGOPREAT_H 2 #define MESGOPREAT_H 3 #include<unistd.h> 4 #include<sys/types.h> 5 #include<sys/wait.h> 6 #include <sys/stat.h> 7 #include<stdio.h> 8 #include<stdlib.h> 9 #include<errno.h> 10 #include<string.h> 11 #include <fcntl.h> //O_RDONLY 12 #include<limits.h> //PIPE_BUF 13 #include <QtCore> 14 #define MAXLINE 4088 15 #define FILE_MODE (S_IRUSR | S_IWUSR |S_IRGRP | S_IROTH) 16 #define READ_FIFO "/tmp/fifo.test1" //本端用来打开读 17 #define WRITE_FIFO "/tmp/fifo.test2"//本端用来打开写 18 19 //另一端如下定义 20 21 //#define WRITE_FIFO "/tmp/fifo.test1" //本端用来打开读 22 //#define READ_FIFO"/tmp/fifo.test2"//本端用来打开写 23 //#define 24 #define DATASIZE 6 25 #define MAXMESGDATA (sizeof(struct mymesg) - 2 * sizeof(long)) 26 #define MESGHDRSIZE (sizeof(struct mymesg) - MAXMESGDATA) 27 28 typedef struct mymesg{ 29 30 long mesg_type; 31 long mesg_len_data; 32 int data[DATASIZE]; 33 34 }Mesg; 35 Q_DECLARE_METATYPE(Mesg)//用connect函数就需要此宏,和之后的qRegisterMetaType<Mesg>("Mesg");一同使用 36 ssize_t mesg_send(int ,struct mymesg *);//数据发送 37 void Mesg_send(int , struct mymesg *);//数据发送 38 ssize_t mesg_recv(int , struct mymesg *);//数据接收 39 40 #endif // MESGOPREAT_H
下面是这些函数的实现
1 #include"MesgOpreat.h" 2 ssize_t mesg_send(int fd, Mesg * mptr){ 3 4 return(write(fd, mptr, MESGHDRSIZE + mptr -> mesg_len_data)); 5 6 } 7 ssize_t mesg_recv(int fd, Mesg *mptr){ 8 ssize_t len; 9 ssize_t n; 10 if( (n = read(fd, mptr, MESGHDRSIZE)) == 0 ){//读取头部 11 return 0; 12 }else if ( n != MESGHDRSIZE){ //头部长度和标准不一致时执行 13 printf("mesg header expect %d,got %d\n", MESGHDRSIZE, n ); 14 return 0; 15 } 16 if( (len = mptr -> mesg_len_data) > 0){ //在头部中获得传输数据的长度 17 if( (n = read(fd, mptr-> data, len)) != len){ //只取得头部数据指定的数据的长度数据 18 printf("mesg data expect %d, got %d\n", len, n); 19 return 0; 20 } 21 } 22 return n; //返回的是数据部的长度 23 24 } 25 void Mesg_send(int fd, Mesg *mptr){ 26 ssize_t n; 27 if( (n = mesg_send(fd, mptr)) != mptr -> mesg_len_data + MESGHDRSIZE){ 28 printf("mesg send error\n"); 29 return ; 30 } 31 }
每一个对弈窗口会因为等待对方发送数据而卡屏,所以我们将这个阻塞的recive操作放在一个单独的线程里,我们自定义了一个类MonitorThread 它是继承QThread
1 #ifndef MONITORTHREAD_H 2 #define MONITORTHREAD_H 3 #include<QDebug> 4 #include <QThread> 5 #include "MesgOpreat.h" 6 7 class MonitorThread : public QThread 8 { 9 Q_OBJECT 10 public: 11 MonitorThread(QObject *parent); 12 ~MonitorThread(); 13 void run(); 14 15 signals: 16 void dataArived(Mesg); 17 18 protected: 19 20 private: 21 Mesg mesg; 22 int readfifo,dummyfd; 23 }; 24 25 #endif // MONITORTHREAD_H
下面是对MonitorThread类中的一些方法的实现
1 #include "monitorthread.h" 2 3 MonitorThread::MonitorThread(QObject *parent) : 4 QThread(parent) 5 { 6 start(); 7 } 8 MonitorThread::~MonitorThread(){ 9 delete this; 10 } 11 void MonitorThread::run(){ 12 if( (mkfifo(READ_FIFO, FILE_MODE) < 0) && (errno == EEXIST)){ 13 printf("can't create %s\n",READ_FIFO); 14 } 15 if( (mkfifo(WRITE_FIFO, FILE_MODE) < 0) && (errno == EEXIST)){ 16 printf("can't create %s\n",WRITE_FIFO); 17 } 18 qDebug()<<"b"; 19 int n; 20 qDebug()<<"d"; 21 readfifo = open(READ_FIFO, O_RDONLY,0); 22 dummyfd = open(READ_FIFO, O_WRONLY,0);//在这里已经阻塞 23 qDebug()<<"e"; 24 while((n = mesg_recv(readfifo, &mesg)) > 0){ 25 emit dataArived(mesg); 26 } 27 }
主窗体类的定义
1 #ifndef CLIENTMAINWINDOW_H 2 #define CLIENTMAINWINDOW_H 3 #define MAPLENTH 10 4 #include <QMainWindow> 5 #include<QPushButton> 6 #include<QGridLayout> 7 #include "monitorthread.h" 8 #include"MesgOpreat.h" 9 #include<QDebug> 10 #include<QPoint> 11 #include<QMessageBox> 12 class ClientMainWindow : public QMainWindow 13 { 14 Q_OBJECT 15 public: 16 explicit ClientMainWindow(QWidget *parent = 0); 17 ~ClientMainWindow(){ 18 delete this; 19 } 20 signals: 21 public slots: 22 void Mesg_recved(Mesg); 23 void Chess_left_Clicked(); 24 private:/ 25 int flag = 0; 26 int up_col_count = 0, low_col_count = 0, left_row_count = 0,right_row_count = 0, 27 left_up_count = 0, right_up_count = 0, left_low_count = 0, right_low_count = 0 ; 28 int judge(); 29 void ergodic(int x, int y); 30 void ergodic_up(int x, int y);//基于某一点向上第归遍历 31 void ergodic_down(int x, int y);//基于某一点向下第归遍历 32 void ergodic_left(int x, int y);//基于某一点向左第归遍历 33 void ergodic_right(int x, int y);//基于某一点向右第归遍历 34 void ergodic_left_up(int x, int y);//基于某一点向左上第归遍历 35 void ergodic_left_low(int x, int y);//基于某一点左下第归遍历 36 void ergodic_right_up(int x, int y); 37 void ergodic_right_low(int x, int y); 38 void Count_to_0(); 39 int return_judge(int x, int y);//判断第归结束的标志 40 ///// 41 42 int writefifo; 43 QPushButton *button[MAPLENTH][MAPLENTH]; 44 MonitorThread *thread; 45 Mesg mesg; 46 QGridLayout *layout; 47 void Init_Button(); 48 int map[MAPLENTH][MAPLENTH] = {}; 49 void StartGame();//创建命名管道与初始打开 50 void Listen_thread(); 51 }; 52 53 #endif // CLIENTMAINWINDOW_H
主窗体类中方法的实现
1 #include "clientmainwindow.h" 2 3 ClientMainWindow::ClientMainWindow(QWidget *parent) : 4 QMainWindow(parent) 5 { 6 qDebug()<<"a"; 7 this->setGeometry(300,600,494,521); 8 setWindowFlags(windowFlags()& ~Qt::WindowMaximizeButtonHint);//禁止最大化 9 setFixedSize(this->width(), this->height());//禁止最大化 10 StartGame(); 11 qRegisterMetaType<Mesg>("Mesg"); 12 Init_Button(); 13 } 14 15 void ClientMainWindow:: Chess_left_Clicked(){ 16 qDebug()<<"left"; 17 int p_x, p_y; 18 QPoint Chess_Point; 19 QPushButton* btn= qobject_cast<QPushButton*>(sender()); 20 Chess_Point = btn->pos(); 21 p_x = (Chess_Point.y() - 13) / 50; 22 p_y = (Chess_Point.x() - 11) / 48; 23 qDebug()<<"p_x"<<p_x ; 24 qDebug()<<"p_y"<<p_y; 25 if(map[p_x][p_y] != 0){ 26 QMessageBox::about(NULL, "wring", "Occupied"); 27 return; 28 } 29 if(flag != 0){ 30 QMessageBox::about(NULL,"woring", "you have inputed"); 31 return; 32 } 33 flag = 1; 34 button[p_x][p_y]->setIcon(QIcon(":/picture/Black.bmp")); 35 map[p_x][p_y]= 2; 36 mesg.mesg_type =1; 37 mesg.mesg_len_data = DATASIZE* sizeof(int); 38 ergodic(p_x, p_y); 39 mesg.data[0] = p_x; 40 mesg.data[1] = p_y; 41 mesg.data[2] = up_col_count + low_col_count + 1; 42 mesg.data[3] = right_row_count + left_row_count + 1; 43 mesg.data[4] = left_up_count + right_low_count + 1; 44 mesg.data[5] = left_low_count + right_up_count + 1; 45 if( (writefifo = open(WRITE_FIFO, O_WRONLY,0)) < 0){ 46 printf("server open writefifo error: %s\n",strerror(errno)); 47 48 } 49 Mesg_send( writefifo, &mesg); 50 if(judge()){ 51 QMessageBox::about(NULL, "wiring","YOU are Winer!"); 52 exit(0); 53 } 54 } 55 void ClientMainWindow::StartGame(){ 56 57 Listen_thread(); 58 59 } 60 61 void ClientMainWindow:: Listen_thread(){ 62 thread = new MonitorThread(this); 63 connect(thread, SIGNAL(dataArived(Mesg)), 64 this, SLOT(Mesg_recved(Mesg))); 65 qDebug()<<"c"; 66 } 67 68 void ClientMainWindow:: Init_Button(){ 69 70 layout = new QGridLayout; 71 int pos_x = 0, pos_y = 0; 72 for(int row = 0; row < MAPLENTH; row++){ 73 for(int col = 0; col < MAPLENTH; col++){ 74 button[row][col] = new QPushButton(this); 75 pos_x = 48 * col + 3; 76 pos_y = 47 * row + 2; 77 button[row][col]->setGeometry(pos_x,pos_y,40,40); //设置button的坐标与大小 78 button[row][col]->setMaximumSize(40,40); 79 button[row][col]->setMinimumSize(40,40); 80 layout->addWidget(button[row][col],row,col); 81 QObject::connect(button[row][col],SIGNAL(clicked()),this,SLOT(Chess_left_Clicked())); 82 } 83 } 84 QWidget * widget = new QWidget(this) ; 85 this->setCentralWidget(widget) ; 86 widget->setLayout( layout) ; 87 } 88 89 90 void ClientMainWindow::Mesg_recved(Mesg _mesg){ 91 92 mesg = _mesg;//获得的消息 93 button[mesg.data[0]][mesg.data[1]]->setIcon(QIcon(":/picture/White.bmp")); 94 map[mesg.data[0]][mesg.data[1] ]= 1; 95 // ergodic(mesg.data[0], mesg.data[1]); 96 if(mesg.data[2] >= 5 || mesg.data[3] >= 5 || mesg.data[4]>= 5 || mesg.data[5] >= 5){ 97 QMessageBox::about(NULL, "wiring","Distinnation is Winer!"); 98 exit(0); 99 } 100 flag = 0; 101 } 102 103 104 105 int ClientMainWindow::judge(){ 106 if( (up_col_count + low_col_count + 1) >= 5 || 107 (right_row_count + left_row_count + 1) >= 5|| 108 (left_up_count + right_low_count + 1) >= 5|| 109 (left_low_count + right_up_count + 1) >= 5){ 110 return 1; 111 } 112 Count_to_0(); 113 return 0; 114 } 115 116 int ClientMainWindow::return_judge(int x, int y){//判断第归结束 117 if(x < 0 || x >= MAPLENTH || y < 0 || y>= MAPLENTH ){ 118 return 1; 119 } 120 return 0; 121 } 122 void ClientMainWindow::Count_to_0(){ 123 up_col_count = 0; 124 low_col_count = 0; 125 right_row_count = 0; 126 left_row_count = 0; 127 left_up_count = 0; 128 right_up_count = 0 ; 129 left_low_count = 0; 130 right_low_count = 0; 131 } 132 133 134 void ClientMainWindow::ergodic_right_low(int x, int y){ 135 if( return_judge(x, y)){ 136 return; 137 } 138 if(map[x][y] != 0 && map[x + 1 ][y + 1] == map[x][y]){//向右下遍历right_low 139 right_low_count++; 140 ergodic_right_low(x + 1 , y + 1); 141 } 142 } 143 void ClientMainWindow::ergodic_left_low(int x, int y){ 144 if( return_judge(x, y)){ 145 return; 146 } 147 if(map[x][y] != 0 && map[x + 1 ][y - 1] == map[x][y]){//向左下遍历left_low 148 left_low_count++; 149 ergodic_left_low(x + 1 , y - 1); 150 } 151 } 152 void ClientMainWindow::ergodic_right_up(int x, int y){ 153 if( return_judge(x, y)){ 154 return; 155 } 156 if(map[x][y] != 0 && map[x - 1 ][y + 1] == map[x][y]){//向右上遍历right_up 157 right_up_count++; 158 ergodic_right_up(x - 1 , y + 1); 159 } 160 } 161 void ClientMainWindow::ergodic_left_up(int x, int y){ 162 if( return_judge(x, y)){ 163 return; 164 } 165 if(map[x][y] != 0 && map[x - 1 ][y - 1] == map[x][y]){//向左上遍历left_up 166 left_up_count++; 167 ergodic_left_up(x - 1 , y - 1); 168 } 169 } 170 void ClientMainWindow::ergodic_right(int x, int y){ 171 if( return_judge(x, y)){ 172 return; 173 } 174 if(map[x][y] != 0 && map[x][y + 1] == map[x][y]){//向右遍历right 175 right_row_count++; 176 ergodic_right(x , y + 1); 177 } 178 } 179 void ClientMainWindow::ergodic_left(int x, int y){ 180 if( return_judge(x, y)){ 181 return; 182 } 183 if(map[x][y] != 0 && map[x][y - 1] == map[x][y]){//向左遍历left 184 left_row_count++; 185 ergodic_left(x , y - 1); 186 } 187 } 188 void ClientMainWindow::ergodic_down(int x, int y){ 189 if( return_judge(x, y)){ 190 return; 191 } 192 if(map[x][y] != 0 && map[x + 1][y] == map[x][y]){ 193 low_col_count++; 194 ergodic_down(x + 1, y); 195 } 196 } 197 void ClientMainWindow::ergodic_up(int x, int y){ 198 if( return_judge(x, y)){ 199 return; 200 } 201 if(map[x][y] != 0 && map[x-1][y] == map[x][y]){//向上查询up 202 up_col_count++; 203 ergodic_up(x - 1, y); 204 } 205 } 206 void ClientMainWindow::ergodic(int x, int y){ //各个方向进行分治第归遍历 207 ergodic_up( x, y);//向上 208 ergodic_down( x, y);//向下 209 ergodic_left(x, y); //向左 210 ergodic_right(x, y); 211 ergodic_left_up( x, y); 212 ergodic_left_low( x, y); 213 ergodic_right_up(x, y); 214 ergodic_right_low(x, y); 215 }
另一端只需要改变 MesgOpreat.h中的宏READ_FIFO和WRITE_FIFO交换一下就可以与此端通信