首先看一下实现结果:

  >>功能

     (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网络编程之简单聊天对话框的更多相关文章

  1. QT TCP网络编程

    首先介绍一下TCP:(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议.相比而言UDP,就是开放式.无连接.不可靠的传输层 ...

  2. python网络编程——实现简单聊天

    通过socket建立简单的聊天工具 server.py import socket import threading import time s = socket.socket(socket.AF_I ...

  3. JAVA TCP网络编程学习笔记

    一.JAVA网络编程概述 网络应用程序,就是在已实现网络互联的不同计算机上运行的应用程序,这些程序之间可以相互交换数据.JAVA是优秀的网络编程语言,Java网络编程的类库位于java.net包中.J ...

  4. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    [Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...

  5. Java利用TCP编程实现简单聊天室

    前言: 本文是我在学习尚学堂JAVA300集第二季网络编程部分仿照视频内容实现而成 具体可以去尚学堂官网观看视频学习 一.实现思路 实现聊天室的最核心部分就是JAVA的TCP网络编程. TCP 传输控 ...

  6. TCP网络编程

    TCP网络编程  与UDP不同的是TCP是通过客服端和服务端的方式来传输数据的.客服端:public class TCPClient { /**     * @param args     * @th ...

  7. Linux下TCP网络编程与基于Windows下C#socket编程间通信

    一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...

  8. 简述TCP网络编程本质

    基于事件的非阻塞网络编程是编写高性能并发网络服务程序的主流模式,头一次使用这种模式编程需要转换思维模式 .把原来的"主动调用recv()来接收数据,主动调用accept()来接受连接,主动调 ...

  9. Java - TCP网络编程

    Java - TCP网络编程 Server 逻辑思路: 创建ServerSocket(port),然后服务器的socket就启动了 循环中调用accept(),此方法会堵塞程序,直到发现用户请求,返回 ...

随机推荐

  1. Implementation of Message Receiver

  2. [转]Redis内部数据结构详解-sds

    本文是<Redis内部数据结构详解>系列的第二篇,讲述Redis中使用最多的一个基础数据结构:sds. 不管在哪门编程语言当中,字符串都几乎是使用最多的数据结构.sds正是在Redis中被 ...

  3. [转]调试利器-SSH隧道

    在开发微信公众号或小程序的时候,由于微信平台规则的限制,部分接口需要通过线上域名才能正常访问.但我们一般都会在本地开发,因为这能快速的看到源码修改后的运行结果.但当涉及到需要调用微信接口时,由于不和你 ...

  4. Atitit s2018.5 s5 doc list on com pc.docx  v2

    Atitit s2018.5 s5  doc list on com pc.docx  Acc  112237553.docx Acc Acc  112237553.docx Acc baidu ne ...

  5. Pandas基础(十一)时间序列

    1. pandas时间序列:时间索引 2. pandas时间序列数据结构 2.1 定期序列 3. 频率和偏移 4. 重采样,转移,加窗口 4.1 重采样及频率转换 4.2 时间移动 4.3 滚动窗口 ...

  6. 数据类型表(DELPHI、C++)

    delphi整型数据表 Integer -2147483648..2147483647 signed 32-bit Cardinal 0..4294967295 unsigned 32-bit Sho ...

  7. 在Ubuntu主机下实现与Windows虚拟机共享文件夹

    一.概述 由于要实现Ubuntu主机中的一些文件与Windows虚拟机共享,因此要创建一个共享文件夹映射到虚拟机中. 网上许多都是Windows主机+Linux虚拟机的配置,在此分享主机是Linux的 ...

  8. 【教程】Win7-64位安装OpenSSL详细过程

    1.下载ActivePerl  5.24.0.2400 http://www.activestate.com/activeperl/downloads 图片:ActivePerl-5.24.0.240 ...

  9. CDN 服务域名解析配置

    记录类型请选择为CNAME: 主机记录即加速域名的前缀,例如:   如果您的加速域名为... 前缀为... testcdn.aliyun.com testcdn www.aliyun.com www ...

  10. laravel5.8笔记六:公共函数和常量设置

    公共函数 创建bootstrap/common.php <?php // 发送短信 function sendSMS($mobile){ } // 发送邮件 function sendMail( ...