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没有建立链接所有效果不友好