Ubuntu上Qt+Tcp网络编程之简单聊天对话框
首先看一下实现结果:
>>功能:
(1)服务器和客户端之间进行聊天通信;
(2)一个服务器可同时给多个客户端发送消息;(全部连接时)
也可以只给特定的客户端发送消息;(连接特定IP)
(3)可发送任意字符,包括中文;(原来参考的程序不能发中文)

>>后续拓展:
(1)不同客户端之间能否进行通信?
(2)发完消息之后如何清空发送区?
(3)如何完善登录注册功能?
(4)如何更换界面背景及颜色?
…………
程序:
注意:首先需要在每个工程.pro文件里加上一句
QT += network
1.mytcpclient.h
#ifndef MYTCPCLIENT_H
#define MYTCPCLIENT_H #include <QMainWindow>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox> namespace Ui {
class MyTcpClient;
} class MyTcpClient : public QMainWindow
{
Q_OBJECT public:
explicit MyTcpClient(QWidget *parent = );
~MyTcpClient(); private:
Ui::MyTcpClient *ui;
QTcpSocket *tcpClient; private slots:
//客户端槽函数
void ReadData();
void ReadError(QAbstractSocket::SocketError); void on_btnConnect_clicked();
void on_btnSend_clicked();
void on_btnClear_clicked();
}; #endif // MYTCPCLIENT_H
mytcpclient.h
2.mytcpclient.cpp
#include "mytcpclient.h"
#include "ui_mytcpclient.h" MyTcpClient::MyTcpClient(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MyTcpClient)
{
ui->setupUi(this); //初始化TCP客户端
tcpClient = new QTcpSocket(this); //实例化tcpClient
tcpClient->abort(); //取消原有连接
ui->btnConnect->setEnabled(true);
ui->btnSend->setEnabled(false); connect(tcpClient, SIGNAL(readyRead()), this, SLOT(ReadData()));
connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)), \
this, SLOT(ReadError(QAbstractSocket::SocketError)));
} MyTcpClient::~MyTcpClient()
{
delete ui;
} void MyTcpClient::ReadData()
{
//QByteArray buffer = tcpClient->readAll(); //by me
QByteArray buffer; //add by me
buffer.resize(tcpClient->bytesAvailable());//add by me
tcpClient->read(buffer.data(),buffer.size());//add by me
if(!buffer.isEmpty())
{
QString msg = QString::fromLocal8Bit(buffer.data());//add by me
ui->edtRecv->append(msg); //buffer -> msg ; by me
}
} void MyTcpClient::ReadError(QAbstractSocket::SocketError)
{
tcpClient->disconnectFromHost();
ui->btnConnect->setText(tr("连接"));
QMessageBox msgBox;
msgBox.setText(tr("failed to connect server because %1").arg(tcpClient->errorString()));
msgBox.exec();
} void MyTcpClient::on_btnConnect_clicked()
{
if(ui->btnConnect->text()=="连接")
{
tcpClient->connectToHost(ui->edtIP->text(), ui->edtPort->text().toInt());
if (tcpClient->waitForConnected()) // 连接成功则进入if{}
{
ui->btnConnect->setText("断开");
ui->btnSend->setEnabled(true);
}
}
else
{
tcpClient->disconnectFromHost();
if (tcpClient->state() == QAbstractSocket::UnconnectedState \
|| tcpClient->waitForDisconnected()) //已断开连接则进入if{}
{
ui->btnConnect->setText("连接");
ui->btnSend->setEnabled(false);
}
}
} void MyTcpClient::on_btnSend_clicked()
{
QString data = ui->edtSend->toPlainText();
QByteArray text = data.toLocal8Bit(); //add by me
if(data != "")
{
//tcpClient->write(data.toLatin1()); //qt5出去了.toAscii() //by me
tcpClient->write(text,text.length()); //add by me
}
} void MyTcpClient::on_btnClear_clicked()
{
ui->edtRecv->clear();
}
mytcpclient.cpp
3.mytcpserver.h
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H #include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkInterface>
#include <QMessageBox>
namespace Ui {
class MyTcpServer;
} class MyTcpServer : public QMainWindow
{
Q_OBJECT public:
explicit MyTcpServer(QWidget *parent = );
~MyTcpServer(); private:
Ui::MyTcpServer *ui;
QTcpServer *tcpServer;
QList<QTcpSocket*> tcpClient;
QTcpSocket *currentClient; private slots:
void NewConnectionSlot();
void disconnectedSlot();
void ReadData(); void on_btnConnect_clicked();
void on_btnSend_clicked();
void on_btnClear_clicked();
}; #endif // MYTCPSERVER_H
mytcpserver.h
4.mytcpserver.cpp
#include "mytcpserver.h"
#include "ui_mytcpserver.h" MyTcpServer::MyTcpServer(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MyTcpServer)
{
ui->setupUi(this); tcpServer = new QTcpServer(this);
ui->edtIP->setText(QNetworkInterface().allAddresses().at().toString()); //获取本地IP
ui->btnConnect->setEnabled(true);
ui->btnSend->setEnabled(false); connect(tcpServer, SIGNAL(newConnection()), this, SLOT(NewConnectionSlot()));
} MyTcpServer::~MyTcpServer()
{
delete ui;
}
// newConnection -> newConnectionSlot 新连接建立的槽函数
void MyTcpServer::NewConnectionSlot()
{
currentClient = tcpServer->nextPendingConnection();
tcpClient.append(currentClient);
ui->cbxConnection->addItem(tr("%1:%2").arg(currentClient->peerAddress().toString().split("::ffff:")[])\
.arg(currentClient->peerPort()));
connect(currentClient, SIGNAL(readyRead()), this, SLOT(ReadData()));
connect(currentClient, SIGNAL(disconnected()), this, SLOT(disconnectedSlot()));
} // 客户端数据可读信号,对应的读数据槽函数
void MyTcpServer::ReadData()
{
// 由于readyRead信号并未提供SocketDecriptor,所以需要遍历所有客户端
for(int i=; i<tcpClient.length(); i++)
{
QByteArray buffer; //add by me
buffer.resize(tcpClient[i]->bytesAvailable());//add by me
tcpClient[i]->read(buffer.data(),buffer.size());//add by me
//QByteArray buffer = tcpClient[i]->readAll(); //by me
if(buffer.isEmpty()) continue; static QString IP_Port, IP_Port_Pre;
IP_Port = tr("[%1:%2]:").arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[])\
.arg(tcpClient[i]->peerPort()); // 若此次消息的地址与上次不同,则需显示此次消息的客户端地址
if(IP_Port != IP_Port_Pre)
ui->edtRecv->append(IP_Port); QString msg = QString::fromLocal8Bit(buffer.data());//add by me
ui->edtRecv->append(msg); //buffer -> msg ; by me //更新ip_port
IP_Port_Pre = IP_Port;
}
}
// disconnected -> disconnectedSlot 客户端断开连接的槽函数
void MyTcpServer::disconnectedSlot()
{
//由于disconnected信号并未提供SocketDescriptor,所以需要遍历寻找
for(int i=; i<tcpClient.length(); i++)
{
if(tcpClient[i]->state() == QAbstractSocket::UnconnectedState)
{
// 删除存储在combox中的客户端信息
ui->cbxConnection->removeItem(ui->cbxConnection->findText(tr("%1:%2")\
.arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[])\
.arg(tcpClient[i]->peerPort())));
// 删除存储在tcpClient列表中的客户端信息
tcpClient[i]->destroyed();
tcpClient.removeAt(i);
}
}
}
// 监听--断开
void MyTcpServer::on_btnConnect_clicked()
{
if(ui->btnConnect->text()=="监听")
{
bool ok = tcpServer->listen(QHostAddress::Any, ui->edtPort->text().toInt());
if(ok)
{
ui->btnConnect->setText("断开");
ui->btnSend->setEnabled(true);
}
}
else
{
for(int i=; i<tcpClient.length(); i++)//断开所有连接
{
tcpClient[i]->disconnectFromHost();
bool ok = tcpClient[i]->waitForDisconnected();
if(!ok)
{
// 处理异常
}
tcpClient.removeAt(i); //从保存的客户端列表中取去除
}
tcpServer->close(); //不再监听端口
ui->btnConnect->setText("监听");
ui->btnSend->setEnabled(false);
}
}
// 发送数据
void MyTcpServer::on_btnSend_clicked()
{
QString data = ui->edtSend->toPlainText();
QByteArray text = data.toLocal8Bit(); //add by me
if(data == "") return; // 文本输入框为空时
//全部连接
if(ui->cbxConnection->currentIndex() == )
{
for(int i=; i<tcpClient.length(); i++)
//tcpClient[i]->write(data.toLatin1()); //qt5除去了.toAscii() //by me
tcpClient[i]->write(text,text.length()); //add by me
}
//指定连接
else
{
QString clientIP = ui->cbxConnection->currentText().split(":")[];
int clientPort = ui->cbxConnection->currentText().split(":")[].toInt();
// qDebug() << clientIP;
// qDebug() << clientPort;
for(int i=; i<tcpClient.length(); i++)
{
if(tcpClient[i]->peerAddress().toString().split("::ffff:")[]==clientIP\
&& tcpClient[i]->peerPort()==clientPort)
{
//tcpClient[i]->write(data.toLatin1()); //by me
tcpClient[i]->write(text,text.length()); //add by me
return; //ip:port唯一,无需继续检索
}
}
}
} void MyTcpServer::on_btnClear_clicked()
{
ui->edtRecv->clear();
}
mytcpserver.cpp
5.mytcpclient.ui

6.mytcpserver.ui

Ubuntu上Qt+Tcp网络编程之简单聊天对话框的更多相关文章
- QT TCP网络编程
		
首先介绍一下TCP:(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议.相比而言UDP,就是开放式.无连接.不可靠的传输层 ...
 - python网络编程——实现简单聊天
		
通过socket建立简单的聊天工具 server.py import socket import threading import time s = socket.socket(socket.AF_I ...
 - JAVA TCP网络编程学习笔记
		
一.JAVA网络编程概述 网络应用程序,就是在已实现网络互联的不同计算机上运行的应用程序,这些程序之间可以相互交换数据.JAVA是优秀的网络编程语言,Java网络编程的类库位于java.net包中.J ...
 - 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
		
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
 - Java利用TCP编程实现简单聊天室
		
前言: 本文是我在学习尚学堂JAVA300集第二季网络编程部分仿照视频内容实现而成 具体可以去尚学堂官网观看视频学习 一.实现思路 实现聊天室的最核心部分就是JAVA的TCP网络编程. TCP 传输控 ...
 - TCP网络编程
		
TCP网络编程 与UDP不同的是TCP是通过客服端和服务端的方式来传输数据的.客服端:public class TCPClient { /** * @param args * @th ...
 - Linux下TCP网络编程与基于Windows下C#socket编程间通信
		
一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...
 - 简述TCP网络编程本质
		
基于事件的非阻塞网络编程是编写高性能并发网络服务程序的主流模式,头一次使用这种模式编程需要转换思维模式 .把原来的"主动调用recv()来接收数据,主动调用accept()来接受连接,主动调 ...
 - Java - TCP网络编程
		
Java - TCP网络编程 Server 逻辑思路: 创建ServerSocket(port),然后服务器的socket就启动了 循环中调用accept(),此方法会堵塞程序,直到发现用户请求,返回 ...
 
随机推荐
- ComputeShader中Counter类型的使用
			
接上一篇:https://www.cnblogs.com/hont/p/10122129.html 除了Append类型对应的Consume/AppendStructuredBuffer还有一个Cou ...
 - 8款基于Jquery的WEB前端动画特效
			
1.超炫酷的30个jQuery按钮悬停动画 按钮插件是最常见的jQuery插件之一,因为它用途广泛,而且配置起来最为方便.今天我们要分享的是30个超炫酷的jQuery悬停按钮动画,当我们将鼠标滑过按钮 ...
 - org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang
			
HTTP Status 500 - Handler processing failed; nested exception is java.lang.AbstractMethodError: org. ...
 - Specified version of key is not available (44)
			
-- ::, ERROR [HiveServer2-Handler-Pool: Thread-]: transport.TSaslTransport (TSaslTransport.java:open ...
 - awk按顺序去除重复行
			
# root @ c7bit1 in ~ [16:43:40] $ cat test a b c d b g # root @ c7bit1 in ~ [16:46:27] C:2 $ awk '!x ...
 - mac下安装mysql5.7.18,连接出现Access denied for user 'root'@'localhost' (using password: YES)
			
mac下,mysql5.7.18连接出错,错误信息为:Access denied for user 'root'@'localhost' (using password: YES) ()里面的为she ...
 - 《effective Go》读后记录:GO基础
			
一个在线的Go编译器 如果还没来得及安装Go环境,想体验一下Go语言,可以在Go在线编译器 上运行Go程序. 格式化 让所有人都遵循一样的编码风格是一种理想,现在Go语言通过gofmt程序,让机器来处 ...
 - Ubuntu下安装open-falcon-v0.2.1
			
在Ubuntu下安装open-falcon和Centos下安装的方法有点区别,因为Ubuntu使用的包管理器是apt-get,而Centos下使用的是Yum,建议不要再Ubuntu下使用yum 建议自 ...
 - JS字符串常用方法总结
			
1.toLowerCase(): 把字符串转为小写,返回新的字符串. var str="Hello World"; var str1=str.toLowerCase(); cons ...
 - 赵雅智_Swift(4)_断言
			
可选能够让你推断值是否存在.你能够在代码中优雅地处理值缺失的情况.然而,在某些情况下,假设值缺失或者值并不满足特定的条件.你的代码可能并不须要继续执行.这时.你能够在你的代码中触发一个断言(asser ...