计算机网络课程设计(一)网络聊天程序的设计与实现

  • 实验题目

网络聊天程序的设计与实现

  • 实验目的

 1、了解Socket通信的原理,学会使用Socket进行简单的网络编程,在此基础上编写一个聊天程序。

2、了解Qt编程,熟悉C++语言。

  • 总体设计

 1、背景知识

套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。用户数据报协议(UDP,User Datagram Protocol)是一种无需建立连接就可以发送封装的 IP 数据包的传输层通信协议。它不提供数据包分组、组装、对数据包进行排序、报文到达确认、流量控制等功能。

Qt 虽然经常被当做一个 GUI 库,用来开发图形界面应用程序,但这并不是 Qt 的全部;Qt 除了可以绘制漂亮的界面(包括控件、布局、交互),还包含很多其它功能,比如多线程、访问数据库、图像处理、音频视频处理、网络通信、文件操作等,这些 Qt 都已经内置了。

2、基本原理

Socket是一种“打开—读/写—关闭”模式的实现,服务器和客户端各自维护一个“文件”,在建立连接打开后,可以向文件写入内容供对方读取或者读取对方的内容,通讯结束时关闭文件。

Socket在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口,供应用层调用实现进程在网络中的通信。

Socket保证了不同计算机之间的通信,对于网站,通信模型是服务器与客户端之间的通信。两端都建立一个socket对象,然后通过socket对象对数据进行传输。通常服务器处于一个无限循环,等待客户端的连接。

3、模块介绍

(1)服务器端:监听本网络上的所有Ip,如有连接请求,则通过连接,与客户端进行一对一通信。

(2)客户端:通过给定的端口号与Ip地址连接到服务器端,与服务器端进行通信。

 4、设计步骤

(1)服务端

  • 加载套接字库,创建套接字(QTcpSocket)
  • 绑定套接字到一个 IP 地址和一个端口上(bind())
  • 将套接字设置为监听模式等待连接请求(listen())
  • 请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept())
  • 用返回的套接字和客户端进行通信(send())
  • 返回,等待另一连接请求
  • 关闭套接字,关闭加载的套接字库

(2)客户端 

  • 加载套接字库,创建套接字(QTcpSocket)
  • 向服务器发出连接请求(connect())
  • 和服务器端进行通信(send())
  • 关闭套接字,关闭加载的套接字库

 

  • 详细设计

1、程序流程图

计算机网络课程设计(一)网络聊天程序的设计与实现_第1张图片

2、代码

 (1)服务器端

代码组成:

计算机网络课程设计(一)网络聊天程序的设计与实现_第2张图片

server.h

#ifndef SERVER_H
#define SERVER_H

#include 
#include 
#include 

QT_BEGIN_NAMESPACE
namespace Ui { class server; }
QT_END_NAMESPACE

class server : public QMainWindow
{
    Q_OBJECT

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

private:
    Ui::server *ui;
    QTcpServer *Server;
    QTcpSocket *Socket;
private slots:
    void Listen();
    void send();
    void newConnect();
    void Read_data();
    void DisConnect();

};
#endif // SERVER_H

 main.cpp

#include "server.h"

#include 

int main(int argc, char *argv[])
{

    QApplication a(argc, argv);
    server w;
    w.show();
    return a.exec();
}

 server.cpp

#include "server.h"
#include "ui_server.h"
#include 


server::server(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::server)
{
    ui->setupUi(this);
    ui->Port->setText("2770");
    connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(Listen()));
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(send()));

}

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

void server::Listen(){
        Server = new QTcpServer();
        //int port = ui->Port->text().toInt();
        if(!Server->listen(QHostAddress::Any, 2770))
        {
            QMessageBox::information(this, "QT网络通信", "服务器端监听失败!");
            return;
        }
        else
        {
            QMessageBox::information(this, "QT网络通信", "服务器监听成功!");
        }
        connect(Server, SIGNAL(newConnection()), this, SLOT(newConnect()));
}
void server::send(){
        qint64 writes=Socket->write(ui->textEdit->toPlainText().toLatin1());
        bool Bool=Socket->flush();
        if(writes==-1&&Bool!=1)
        {
            QMessageBox::warning(this, "QT网络通信", "发送数据失败,请重新发送!");
            return;
        }
        ui->listWidget->addItem(QString(ui->textEdit->toPlainText()).toLocal8Bit());
        ui->textEdit->clear();
}
void server::Read_data(){
    QByteArray array;
    array.resize(Socket->bytesAvailable());//根据可读数据来设置空间大小
    array=Socket->readLine();
    ui->listWidget->addItem("【客户端】:"+array);
}
void server::newConnect(){
    Socket=Server->nextPendingConnection();
    if(!Socket){
        QMessageBox::warning(this, "warning", "未正确获取客户端连!");
               return;
           }
           else
           {
               QMessageBox::information(this, "QT网络通信", "成功接受客户端的连接");
           connect(Socket, SIGNAL(readyRead()), this, SLOT(Read_data()));
               connect(Socket, SIGNAL(disconnected()), this, SLOT(DisConnect()));

    }
}
void server::DisConnect(){
    QMessageBox::information(this, "QT网络通信", "与客户端的连接断开");
        return;
}

 server.ui



 server
 
  
   
    0
    0
    465
    556
   
  
  
   server
  
  
   
    
     
      20
      410
      301
      51
     
    
   
   
    
     
      340
      440
      75
      23
     
    
    
     发送
    
   
   
    
     
      20
      40
      81
      20
     
    
    
     服务端端口号
    
   
   
    
     
      110
      40
      113
      20
     
    
   
   
    
     
      240
      40
      75
      23
     
    
    
     初始化
    
   
   
    
     
      20
      80
      301
      311
     
    
   
  
  
   
    
     0
     0
     465
     23
    
   
  
  
 
 
 

 (2)客户端

代码组成:

计算机网络课程设计(一)网络聊天程序的设计与实现_第3张图片

client.h

#ifndef CLIENT_H
#define CLIENT_H

#include 
#include 
QT_BEGIN_NAMESPACE
namespace Ui { class client; }
QT_END_NAMESPACE

class client : public QMainWindow
{
    Q_OBJECT

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

private:
    Ui::client *ui;
private slots:
    void connection();
    void send();
    void read_data();
private:
    QTcpSocket *Socket;
};
#endif // CLIENT_H

 main.cpp

#include "client.h"

#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    client w;
    w.show();
    return a.exec();
}

client.cpp

#include "client.h"
#include "ui_client.h"
#include 
#include 
#include 


client::client(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::client)
{

    ui->setupUi(this);
    ui->Ip->setText("127.0.0.1");
    ui->Port->setText("2770");
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(connection()));
    connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(send()));
}

client::~client()
{
    delete ui;
}
void client::connection(){
    Socket = new QTcpSocket(this);
        QString ip = ui->Ip->text();
      //  int port = ui->Port->text().toInt();
        Socket->connectToHost(QHostAddress("127.0.0.1"), 2770);
        if(!Socket->waitForConnected(30000))
        {
            QMessageBox::warning(this, "warning", "连接服务端失败!");
            return;
        }
        QMessageBox::information(this,"Qt","success!");
         connect(Socket, SIGNAL(readyRead()), this, SLOT(read_data()));
}
void client::send(){
    //获取TextEdit控件中的内容
       QString data=ui->send->toPlainText().toUtf8();
       QByteArray ba=data.toLocal8Bit();
       int sendRe = Socket->write(ba);
       bool bools=Socket->flush();
       if(sendRe == -1&&bools!=1)
       {
            QMessageBox::information(this, "QT网络通信", "向服务端发送数据失败!");
            return;
       }
       ui->listWidget->addItem(QString(ui->send->toPlainText()).toLocal8Bit());
       ui->send->clear();


}
void client::read_data(){
            QByteArray array;
            array.resize(Socket->bytesAvailable());//根据可读数据来设置空间大小
            array=Socket->readLine();
            ui->listWidget->addItem("【服务端】:"+array);


}

client.ui



 client
 
  
   
    0
    0
    373
    573
   
  
  
   client
  
  
   
    
     
      20
      30
      61
      21
     
    
    
     服务端IP
    
   
   
    
     
      20
      70
      81
      21
     
    
    
     服务端端口号
    
   
   
    
     
      100
      30
      113
      20
     
    
   
   
    
     
      100
      70
      113
      20
     
    
   
   
    
     
      20
      360
      271
      51
     
    
   
   
    
     
      240
      50
      75
      23
     
    
    
     连接
    
   
   
    
     
      250
      430
      75
      23
     
    
    
     发送
    
   
   
    
     
      20
      100
      271
      241
     
    
   
  
  
   
    
     0
     0
     373
     23
    
   
  
  
 
 
 

  • 实验结果与分析

1、实验结果

 计算机网络课程设计(一)网络聊天程序的设计与实现_第4张图片

计算机网络课程设计(一)网络聊天程序的设计与实现_第5张图片

 计算机网络课程设计(一)网络聊天程序的设计与实现_第6张图片

 2、分析

首先必须要打开服务端,让服务器建立监听,然后再打开客户端,与服务器建立连接,客户端可以向服务器先发送消息,然后收到服务器的回复后又可以继续发送。有一个缺点是,必须要一来一回的聊天,客户端不能向服务器发送多条消息,同样服务器也不能。

  • 小结与心得体会

本实验是第一个实验,刚开始拿到这题,完全没有一点思路,看了附录一后,逐渐对网络通信有了一点了解。在此之前我们没有接触过使用socket接口实现网络协议的一系列编程思想,对TCP和UDP的了解也仅限于理论知识,完全不会运用到实验中。在实验一中,我学会使用socket实现通信,也了解了一系列编程协议,同时从整体上对于winsock的使用流程有了更深一步的了解,通过阅读源码,对于TCP/IP协议在程序运行的实质和流程有了根深的理解。

你可能感兴趣的:(qt,计算机网络,c++)