Windows Qt客户端与虚拟机Linux服务端的连接

本文详细介绍了如何在CentOS7中检查和配置firewalld防火墙以允许特定端口(如3666),以及提供了一个使用epoll在服务端和QTcpSocket在Windows客户端之间的连接示例。
摘要由CSDN通过智能技术生成

检查特定端口是否被防火墙允许通行

        在开始建立连接之前需要查看服务端监听的端口是否被允许通行(以3666端口为例),如果输出结果为空,则表示该端口没有被允许通行。

firewall-cmd --list-ports | grep 3666

为特定端口添加防火墙规则        

如果没有被允许通行,那么是无法成功建立连接的,需要设置端口通行。

        在 CentOS 7 中,你可以使用 firewall-cmd 命令来配置 firewalld 服务,允许特定端口通过防火墙。以下是为特定端口添加防火墙规则的步骤:

1、添加临时规则(重启后失效)

        假设开放3666端口,输入以下指令:

sudo firewall-cmd --zone=public --add-port=3666/tcp

2、添加永久规则(重启后仍然有效)

        如果你想要永久开放端口,需要加上 --permanent 标志。例如,永久开放TCP端口3666,使用以下命令:

sudo firewall-cmd --zone=public --add-port=3666/tcp --permanent

        完成添加规则后,为了让永久规则生效,需要重新加载防火墙的配置:

sudo firewall-cmd --reload

添加完成后可使用以下指令查看端口是否开放:

firewall-cmd --list-ports | grep 3666

出现以下这种情况代表成功开放

进行连接

        完成以上操作后,就可以开始进行客户端与服务端的连接了,接下来我将用一个例子来演示:

服务端代码(在虚拟机Centos7上使用epoll实现):

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<sys/epoll.h>
int main(int argc,char *argv[]){
	int lfd,cfd;
	lfd=socket(AF_INET,SOCK_STREAM,0);
	if(lfd==-1){
		perror("socket error");
		exit(1);
	}
	int opt=1;
	setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//设置端口复用
	struct sockaddr_in addr;
	addr.sin_family=AF_INET;
	addr.sin_port=htons(3666);
	addr.sin_addr.s_addr=INADDR_ANY;
	int ret=bind(lfd,(struct sockaddr*)&addr,sizeof(addr));
	if(ret==-1){
		perror("bind error");
		exit(1);
	}
	ret=listen(lfd,128);
	if(ret==-1){
		perror("listen error");
		exit(1);
	}
	struct epoll_event ep,eps[2000];
	int epfd=epoll_create(1);
	if(epfd==-1){
		fprintf(stderr,"epoll_create error:%s\n",strerror(epfd));
		exit(1);
	}
	ep.events=EPOLLIN;
	ep.data.fd=lfd;
	ret=epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&ep);
	if(ret==-1){
		fprintf(stderr,"epoll_ctl error:%s\n",strerror(ret));
		exit(1);
	}
	while(1){
		int n=epoll_wait(epfd,eps,2000,-1);
		if(n==-1){
			fprintf(stderr,"epoll_wait error:%s\n",strerror(n));
			exit(1);
		}
		for(int i=0;i<n;i++){
			if(!(eps[i].events&EPOLLIN)){
				continue;
			}
			if(eps[i].data.fd==lfd){
				struct sockaddr_in caddr;
				socklen_t len=sizeof(caddr);
				cfd=accept(lfd,(struct sockaddr*)&caddr,&len);
				if(cfd==-1){
					perror("accept error");
					exit(1);
				}
				char buf[16];
				printf("客户端已连接 ip:%s  port:%d\n",inet_ntop(AF_INET,&caddr.sin_addr,buf,16),ntohs(caddr.sin_port));
				ep.events=EPOLLIN;
				ep.data.fd=cfd;
				int ret=epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ep);
				if(ret==-1){
					fprintf(stderr,"epoll_ctl error:%s\n",strerror(ret));
					exit(1);
				}
			}
			else{
				char buf[1024];
				int n=read(eps[i].data.fd,buf,1024);
				if(n<0){
					perror("read error");
					exit(1);
				}
				else if(n==0){//客户端已关闭
					int ret=epoll_ctl(epfd,EPOLL_CTL_DEL,eps[i].data.fd,NULL);
					if(ret==-1){
						fprintf(stderr,"epoll_ctl error:%s\n",strerror(ret));
						exit(1);
					}
					close(eps[i].data.fd);
					printf("客户端断开连接\n");
				}
				else{
					printf("%s",buf);
					for(int i=0;i<n;i++){
						buf[i]=toupper(buf[i]);
					}
					write(STDOUT_FILENO,buf,n);
					write(eps[i].data.fd,buf,n);
				}
			}
		}
	}
	close(lfd);
	close(epfd);
	return 0;
}

客户端代码(在Windows上使用qt实现)

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpSocket>
#include <QHostAddress>
#include <QHostInfo>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

private:
    QTcpSocket *tcpclient;
protected:
    void closeEvent(QCloseEvent *event);

private slots:
    void connectfunc();
    void disconnectfunc();
    void socketreaddata();
    void on_pushButton_Connect_clicked();
    void on_pushButton_Send_clicked();
    void on_pushButton_Disconnect_clicked();
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    tcpclient=new QTcpSocket(this);
    connect(tcpclient,SIGNAL(connected()),this,SLOT(connectfunc()));
    connect(tcpclient,SIGNAL(disconnected()),this,SLOT(disconnectfunc()));
    connect(tcpclient,SIGNAL(readyRead()),this,SLOT(socketreaddata()));
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_pushButton_Connect_clicked()
{
    QString addr=ui->comboBoxIp->currentText();
    quint16 port=ui->spinBoxPort->value();
    tcpclient->connectToHost(addr,port);
}

void MainWindow::on_pushButton_Send_clicked()
{
    QString strmsg=ui->lineEdit_InputMsg->text();
    ui->plainTextEdit_DispMsg->appendPlainText("[out]:"+strmsg);
    ui->lineEdit_InputMsg->clear();

    QByteArray str=strmsg.toUtf8();
    str.append('\n');
    tcpclient->write(str);

}

void MainWindow::on_pushButton_Disconnect_clicked()
{
    if(tcpclient->state()==QAbstractSocket::ConnectedState)
        tcpclient->disconnectFromHost();
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if(tcpclient->state()==QAbstractSocket::ConnectedState)
    {
        tcpclient->disconnectFromHost();
    }
    event->accept();

}

void MainWindow::connectfunc()
{
    ui->plainTextEdit_DispMsg->appendPlainText("**********已经连接到服务器端**********");
    ui->plainTextEdit_DispMsg->appendPlainText("**********peer address:"+
                                               tcpclient->peerAddress().toString());
    ui->plainTextEdit_DispMsg->appendPlainText("**********peer port:"+
                                               QString::number(tcpclient->peerPort()));

    ui->pushButton_Connect->setEnabled(false);
    ui->pushButton_Disconnect->setEnabled(true);

}
void MainWindow::disconnectfunc()
{
    ui->plainTextEdit_DispMsg->appendPlainText("**********已断开与服务器端的连接**********");

    ui->pushButton_Connect->setEnabled(true);
    ui->pushButton_Disconnect->setEnabled(false);

}
void MainWindow::socketreaddata()
{
    while(tcpclient->canReadLine())
        ui->plainTextEdit_DispMsg->appendPlainText("[in]:"+tcpclient->readLine());

}

客户端界面布局:

   

代码准备就绪后,运行Linux上的服务端,监听开放的端口,Windows客户端连接至该服务端,IP输入虚拟机Linux上的IP(可使用ifconfig查看)和开放的端口。

运行效果如下:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值