@1405010304geshuaishuai
2016-09-29T15:28:58.000000Z
字数 5157
阅读 1548
tcp
ip
网络编程
设计并实现一个GUI小程序,读取(修改、保存)本机名称、IP地址等相关信息。
因为Qt中没有集成修改IP信息的类,所以我们通过外部环境来进行IP设置,子网掩码,DNS等相关信息的设置。首先,我能想到的有两种方法,一种是通过修改注册表来修改IP,后来,被我给否定了,因为我们要想修改IP得找到对应适配器的名称,可是,打开注册表的函数是一个详细的地址值,我没有找到合适的办法向打开地址中传递参数,所以我放弃了第一种方法;第二种方法是通过cmd命令行修改,显然可行,于是我才用了第二种方法。
首先界面的设计,界面设计仿Windows
我的界面是这样式的
界面设计好之后下面就来完成相关功能,从界面中可以看出设置IP的两种方式,一种是自动获取,一般像我们的路由器大多是是采用这种方式,自动有路由器随机分配一个IP 给电脑, 而像一些交换机中我们需要手动的去设置IP也就是静态IP, 我们需要手动设置这也是第二种设置IP的方式。在图中假设逆选择自动获取IP则手动设置框则设为不可用,点击保存即可,实现代码如下:
if(ui->radioButtonAuto->isChecked())
{
/****自动获取IP功能*******/
QString dhcp = "netsh interface ip set address name =\"本地连接\" source=dhcp";
cmd->start(dhcp);
close();
}
其中调用cmd程序代码如下:
/*首先声明class*/
class QProcess;
private:
Ui::myWidget *ui;
QProcess *cmd;
QProcess *cmd2;
QProcess *cmd3;
/*在mywidget中声明*/
cmd=new QProcess;
cmd2=new QProcess;
cmd3=new QProcess;
/*使用时直接这样用*/
cmd->start(***);//其中***代表在dos窗口中执行的cmd命令
第二种方法为手动设置,其中输入框的设置是有限制的比如IP格式是这样式儿的xxx.xxx.xxx.xxx其中xxx介于0-255之间,所以中间需要用到正则表达式,另外本次输入框中的'.'需要自己手动输入,由于时间以及技术有限没有涉及,还请用户自己输入'.',但是IP的输入限制还是涉及到了,正则表达式如下:
QRegExp rx("^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])$");
ui->lineEditIp_2->setValidator(new QRegExpValidator(rx,this));
ui->lineEditMask_2->setValidator(new QRegExpValidator(rx,this));
ui->lineEditGate->setValidator(new QRegExpValidator(rx,this));
ui->lineEditDns->setValidator(new QRegExpValidator(rx,this));
ui->lineEditDns1->setValidator(new QRegExpValidator(rx,this));
这样的话再输入就不会超出限制了。
通过cmd命令将输入框中的信息设置到电脑的代码如下
else if(ui->radioButtonSetIP->isChecked())
{
/****手动设置IP*****/
QString str13=" ";
QString str="netsh interface ip set address name=\"本地连接\" source=static addr=";
QString str1 = ui->lineEditIp_2->text();
QString str2 = "mask=";
QString str3 =ui->lineEditMask_2->text();
QString str4="gateway=";
QString str5=ui->lineEditGate->text();
QString str6=str+str1+str13+str2+str3+str13+str4+str5;
QString str7="netsh interface ip set dns name=\"本地连接\" source=static addr=";
QString str8=ui->lineEditDns->text();
QString str9="register=primary";
QString str10="netsh interface ip add dnsservers \"本地连接\" ";
QString str11=ui->lineEditDns1->text();
QString str12="index=2";
QString str14=str7+str8+str13+str9; //首选DNS
QString str15=str10+str11+str13+str12; //备用DNS
cmd->start(str6); //设置IP
cmd2->start(str14); //设置首选DNS
if(str11.isEmpty())
{}
else
{
cmd3->start(str15);
}
close();
}
获取网卡以及ip信息的函数都有现成的比较简单,Qt已经给封装的很好了,所以在这里不再赘述。
通过本次实验,学会了如何使用Qt设计ui界面,学会了如何通过调用cmd命令来设置IP等相关信息,相信除了本方法以外还会有更好的方法,由于个人水平有限加上时间仓促,没有将输入框中添加‘.’号,后续有时间会更新。还有许多不足,一步一步来,将程序更新为最好。
将第一章的Hello客户服务器程序改成GUI小程序,并实现服务器程序可以同时接收最多5个客户端的访问,实现迭代回声服务器功能,可以循环接收客户消息,实现简单服务器回复功能。
首先界面的设计,服务器程序一般不需要界面,所以设计客户端程序的界面如下
考虑第一个功能,注意同时最多与5个客户端通信,服务端同时与客户端通信需要用到开辟多个线程来实现服务器与多个客户端的通信,迭代回声服务器则需要将服务器接收到客户端发来的消息原封不动地返还给客户端,智能回复则需要进行关键字的搜索,倘若客户端发来的信息中包含服务器预设好的关键字则进行智能返还。
服务器实现多线程通信的代码
//由于同一个进程内的所有线程共享内存和变量,因此在传递参数时需作特殊处理,值传递。
pthread_create(&thread_id, NULL, (void *)client_fun, (void *)connfd); //创建线程
pthread_detach(thread_id); // 线程分离,结束时自动回收资源
网络编程中接受连接请求的套接字创建过程可整理如下:
第一步:调用socket函数创建套接字。
第二步:调用bind函数分配IP地址和端口号。
第三步:调用listen函数转为可接听请求状态。
第四步:调用accept函数受理连接请求。
服务器端与客户端之间的建立连接以及通信过程总结:
服务器端创建套接字后连续调用bind、listen函数进入等待状态,客户端通过调用connect()函数发起连接请求。需要注意的是,客户端只能等到服务器端调用listen函数后才能调用connect函数。同时要清楚,客户端调用connecr函数前,服务器端有可能率先调用accept函数,当然,此时服务器端在调用accept函数时进入阻塞状态(blocking),直到客户端调connect函数为止。
迭代回声服务器核心代码:
while((recv_len = recv(connfd, recv_buf, sizeof(recv_buf), 0)) > 0)
{
printf("recv_buf: %s\n", recv_buf); // 打印数据
send(connfd, recv_buf, recv_len, 0); // 给客户端回数据
}
智能回复服务器核心代码:
void tcp_server1::readdata()
{
QString fromClient = tcpSocket->readAll();
qDebug()<<fromClient;
QString str1="约吗?";
QString str2="约啥?";
QString str3="吃饭";
QString str4="啥油那拉!";
QString str5="嗯,这个问题把伦家给难倒了呢!";
QString str6="你好!";
QString str7="你好";
QString str8="你好,很高兴为您服务!";
QString str9="再见!";
QString str10="再见";
QTextCodec *code=QTextCodec::codecForName("GBK");
QByteArray mes=code->fromUnicode(fromClient);
QByteArray str_2=code->fromUnicode(str2);
QByteArray str_4=code->fromUnicode(str4);
QByteArray str_5=code->fromUnicode(str5);
QByteArray str_9=code->fromUnicode(str9);
QByteArray str_8=code->fromUnicode(str8);
if(mes==str1)
tcpSocket->write(str_2);
else if(mes==str3)
tcpSocket->write(str_4);
else if(mes==str6||mes==str7)
tcpSocket->write(str_8);
else if(mes==str9||mes==str10)
tcpSocket->write(str_9);
else
tcpSocket->write(str_5);
}
从上面可以看出其实很简单,就是字符串匹配,如果匹配到就会按照规定的方式进行回答。
通过本次实验学到了,服务器创建线程对多个客户端进行服务,客户端与服务器的连接,本次实验采用真实环境,即服务端为Linux Debian系统,将服务程序运行在树莓派上,然后通过Windows的客户端来进行访问,进行数据的交换(信息的收发);其次是学会了在客户端与服务器之间的中文信息的传输,核心代码如下
QTextCodec *code=QTextCodec::codecForName("GBK");
QString message=ui->lineEdit_meseg->text();
QByteArray mes=code->fromUnicode(message);
this->tcpSocket->write(mes);
要在main()函数中包含以下信息
#include <QTextCodec>
QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
最后就是字符串的比较,以及在Qt下客户端与服务器之间的连接和数据的收发。
将第二张的Tcp客户服务器程序修改成GUI小程序,并完成P35第6题的功能。
客户端跟前面的一样只是将发送消息的功能屏蔽即可,修改服务器代码,将write函数改为while循环每次致谢一个字符,知道所有字符全部写完,在客户端接收程序需要用到循环等待服务端将数据写完然后进行一次全部将数据读出即可。
修改服务器端代码
while((str_len=write(&message[i++], 1)!=-1)
{
}
修改客户端代码
for(i=0;i<3000;i++)
QString fromClient = tcpSocket->readAll();
`
`
`
通过本次实验了解到服务器一次写一个字符时直达写完为止,客户端一次全部读取的操作,进一步加深对客户端与服务端信息传递的认识。