上文中对面向连接的C/S模型中的服务器进行了简单描述,本文将说明如何编写一个客户端应用程序。与服务器程序不同,客户端程序要求有友好的交互界面,因此本文所示的客户端程序采用Qt和linux C共同完成。客户端的界面部分采用Qt完成,而与服务器间具体的通信部分则通过linux C语言完成。
1.界面设计
通过Qt Designer可快速设计好客户端界面,并对四个按钮所对应的信号和槽函数进行连接。客户端所对应的类为ClientUI。
2.与服务器间通信的编程
由于Qt是对C++的一种扩展,因此我们必须将使用Linux C编写的客户端通信程序封装成类,这里我们将其定义为ClientConnection。
我们已经对客户端的界面和通信部分分别定义了两个类,但是如何将两者结合在一起?方法很简单。将ClientConnection类的对象cli作为ClientUI类的成员,然后在具体的槽函数中对应相应的通信函数。和上文分析服务器编程的方法不同,本文将以分析客户端对应的槽函数的方式来说明如何编写客户端程序。
2.1连接按钮的槽函数
在连接按钮对应的槽函数中,首先创建客户端套接字描述符;然后从输入框中获得服务器的IP地址;再通过connect函数创建一个连接。
connect函数的原型如下:
#include < sys/socket.h > int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
connect函数用于在sockfd套接字上创建一个连接,sockfd即客户端套接字;addr即为服务器端的套接字地址;addrlen为addr的长度。我们将connect函数封装成ClientConnection类中的connectingSocket函数,该成员函数在连接按钮所对应的槽函数中被调用。:
int ClientConnection::connectingSocket() { if (::connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) { return 0; } return 1; }
在该槽函数中,可以这样使用连接函数:
if (cli.connectingSocket() == 1) { ui->statusLabel->setText("connecting to server success!"); } else { ui->statusLabel->setText("ERROR:connecting to server fail!"); //exit(1); }
当客户端连接至服务器成功后,客户端就可以跟服务器端进行数据的传送。
2.2 修改按钮的槽函数
该槽函数的工作比较简单,使得文本编辑区可被编辑。
2.3 应用按钮的槽函数
在该槽函数中,将文本编辑区的数据发送至服务器端;或从服务器接受数据显示在这个文本编辑区中。发送和接受数据的API仍然是send和recv函数,不过这里我们将这两个函数封装成ClientConnection类中的sendData成员和recvData成员:
int ClientConnection::recvData(char *buf) { if ((recvbytes = recv(sockfd, buf, MAX_DATA_NUM, 0)) == -1) { return 0; } buf[recvbytes] = '\0'; return 1; } int ClientConnection::sendData(char *msg, int len) { if (send(sockfd, msg, len, 0) == -1) { printf("send error!\n"); return 0; } return 1; }
这两个成员函数在该槽函数的适当位置被调用。
2.4退出按钮的槽函数
退出按钮的槽函数中只需断开客户端和服务器之间的连接即可。
参考:
1.Qt Assistant
2.Linux C编程实战;童永清 著;人民邮电出版社;