QT和linux服务器跨平台通信

10 篇文章 1 订阅
8 篇文章 0 订阅

QT里面的TCP和UDP都是封装好了,直接用就可以直接上代码

QT客户端

#include <QApplication>
#include <QDialog>
#include "widget.h"
#include <QSqlDatabase>					//头文件
#include <QDebug>
#include <QMessageBox>
#include <QSqlError>
#include <QUdpSocket>
#include <iostream>
bool OpenDatabase()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");   //数据库驱动类型为SQL Server
    qDebug()<<"ODBC driver?"<<db.isValid();
    QString dsn = QString::fromLocal8Bit("sql");      //数据源名称
    db.setHostName("192.168.0.105");                        //选择本地主机,127.0.1.1
    db.setDatabaseName(dsn);                            //设置数据源名称
    db.setUserName("sa");                               //登录用户
    db.setPassword("liutao");                           //密码
    if(!db.open())                                      //打开数据库
    {
        qDebug()<<db.lastError().text();
        QMessageBox::critical(0, QObject::tr("Database error"), db.lastError().text());
        return false;                                   //打开失败
    }
    else
    {
        qDebug()<<"database open success!";
    }
    return true;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QUdpSocket* u = new QUdpSocket;
    std::string str = "hello c++";
    while(1)
    {
        u->writeDatagram(str.c_str(),str.size(),QHostAddress("150.158.146.173"),8088);
        QByteArray array;
        while(u->hasPendingDatagrams())
        {
            array.resize(u->pendingDatagramSize());
            u->readDatagram(array.data(),array.size());
            qDebug() << array;
        }
    }
    return a.exec();
}

Linux下需要直接封装套接字

udp_socket.hpp

#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cassert>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;
class UdpSocket {
	public: 
		UdpSocket() : fd_(-1) {
		}
		bool Socket() {
			fd_ = socket(AF_INET, SOCK_DGRAM, 0);
			if (fd_ < 0) {
				perror("socket");
				return false;
			}
			return true;
		}
		bool Close() {
			close(fd_);
			return true;
		}
		bool Bind(const std::string& ip, uint16_t port) {
			sockaddr_in addr;
			addr.sin_family = AF_INET;
			addr.sin_addr.s_addr = /*inet_addr(ip.c_str())*/ INADDR_ANY;
			addr.sin_port = htons(port);
			int ret = bind(fd_, (sockaddr*)&addr, sizeof(addr));
			if (ret < 0) {
				perror("bind");
				return false;
			}
			return true;
		}
		bool RecvFrom(std::string* buf, std::string* ip = NULL, uint16_t* port = NULL) {
			char tmp[1024 * 10] = {0};
			sockaddr_in peer;
			socklen_t len = sizeof(peer);
			ssize_t read_size = recvfrom(fd_, tmp,
					sizeof(tmp) - 1, 0, (sockaddr*)&peer, &len);
			if (read_size < 0) {
				perror("recvfrom");
				return false;
			}
			// 将读到的缓冲区内容放到输出参数中
			buf->assign(tmp, read_size);
			if (ip != NULL) {
				*ip = inet_ntoa(peer.sin_addr);
			}
			if (port != NULL) {
				*port = ntohs(peer.sin_port);
			}
			return true;
		}
		bool SendTo(const std::string& buf, const std::string& ip, uint16_t port) {
			sockaddr_in addr;
			addr.sin_family = AF_INET;
			addr.sin_addr.s_addr = inet_addr(ip.c_str());
			addr.sin_port = htons(port);
			ssize_t write_size = sendto(fd_, buf.data(), buf.size(), 0, (sockaddr*)&addr, sizeof(addr));
			if (write_size < 0) {
				perror("sendto");
				return false;
			}
			return true;
		}
	private:
		int fd_;
};

udp_server.hpp

#pragma once
#include "udp_socket.hpp"
// C 式写法
// typedef void (*Handler)(const std::string& req, std::string* resp);
// C++ 11 式写法, 能够兼容函数指针, 仿函数, 和 lamda
#include <functional>
typedef std::function<void (const std::string&, std::string* resp)> Handler;
class UdpServer {
	public:
		UdpServer() {
			assert(sock_.Socket());
		}
		~UdpServer() {
			sock_.Close();
		}
		bool Start(const std::string& ip, uint16_t port, Handler handler) {
			// 1. 创建 socket
			// 2. 绑定端口号
			bool ret = sock_.Bind(ip, port);
			if (!ret) {
				return false;
			}
			// 3. 进入事件循环
			for (;;) {
				// 4. 尝试读取请求
				std::string req;
				std::string remote_ip;
				uint16_t remote_port = 0;
				bool ret = sock_.RecvFrom(&req, &remote_ip, &remote_port);
				if (!ret) {
					continue;
				}
				std::string resp;
				// 5. 根据请求计算响应
				handler(req, &resp);
				// 6. 返回响应给客户端
				sock_.SendTo(resp, remote_ip, remote_port);
				printf("[%s:%d] req: %s, resp: %s\n", remote_ip.c_str(), remote_port,
						req.c_str(), resp.c_str());
			}
			sock_.Close();
			return true;
		}
	private:
		UdpSocket sock_;
};

udp_client.hpp

#pragma once
#include "udp_socket.hpp"
class UdpClient
{
public:
    UdpClient(const std::string &ip, uint16_t port) : ip_(ip), port_(port)
    {
        assert(sock_.Socket());
    }
    ~UdpClient()
    {
        sock_.Close();
    }
    bool RecvFrom(std::string *buf)
    {
        return sock_.RecvFrom(buf);
    }
    bool SendTo(const std::string &buf)
    {
        return sock_.SendTo(buf, ip_, port_);
    }

private:
    UdpSocket sock_;
    // 服务器端的 IP 和 端口号
    std::string ip_;
    uint16_t port_;
};

在linux下的客户端测试代码

#include<iostream>
using namespace std;
#include "udp_client.hpp"

int main(int argc,char** argv)
{
    UdpClient client(argv[1], atoi(argv[2]));
    while(1)
    {
        client.SendTo("hello world");
    }
    
}

server.cc

#include<iostream>
using namespace std;
#include"udp_server.hpp"
void Translate(const std::string& req, std::string* resp)
{
    *resp = "hello world too";
    cout << req << " " << *resp << endl;
}
int main(int argc,char** argv)
{
    UdpServer server;
    sleep(10);
    server.Start(argv[1], atoi(argv[2]), Translate);
    return 0;
}

makefile 

.PHONY:all
all:server client

server:server.cc
	g++ -o $@ $^ -std=c++11 
client:client.cc
	g++ -o $@ $^ -std=c++11 
.PHONY:clean
clean:
	rm -rf server client

亲测有效

 

 服务器显示的私有网络的公网入口,UDP没有建立链接所有效果不友好

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值