精华内容
下载资源
问答
  • Qt 多线程服务器与客户端

    千次阅读 2018-10-17 14:36:14
    多线程服务器与客户端

    • 服务器
    • 客户端

    思路

    刚开始学是把tcp放到主线程的.
    现在多线程就是把tcp放到新开辟的线程即可,和放在主线程的操作一样

    服务器

    • 重写void QTcpServer :: incomingConnection(qintptr socketDescriptor)函数
      有新连接的时候QTcpServer先调用此虚函数,参数socketDescriptor是原始的套接字.获得原始套接字之后我们便可以进行处理

    myserver.h

    #ifndef MYSERVER_H
    #define MYSERVER_H
    
    #include <QTcpServer>
    
    class MyThread;
    
    class MyServer : public QTcpServer
    {
        Q_OBJECT
    public:
        MyServer(QWidget *parent = 0);
    
        virtual void incomingConnection(qintptr socketDescriptor);
    signals:
        void sendReceivedFilename(const QString &fileName);
    };
    
    #endif // MYSERVER_H
    
    

    myserver.cpp

    #include "myserver.h"
    #include "mythread.h"
    #include <QDebug>
    
    MyServer::MyServer(QWidget *parent)
    {
    
    }
    
    void MyServer::incomingConnection(qintptr socketDescriptor)
    {
        static int i = 0;
        MyThread *thread = new MyThread(0, socketDescriptor);
        thread->start();
    
        connect(thread, &MyThread::finished, [&]{
            qDebug() << "thread is over";
        });
        connect(thread, &MyThread::finished, &MyThread::deleteLater);
        connect(thread, &MyThread::sendReceivedFileName, this, &MyServer::sendReceivedFilename);
    }
    
    

    mythread.h

    #ifndef MYTHREAD_H
    #define MYTHREAD_H
    
    #include <QThread>
    #include <QWidget>
    
    class MyTcpSocket;
    
    class MyThread : public QThread
    {
        Q_OBJECT
    public:
        MyThread(QWidget *parent, qintptr socket);
    
    private:
        qintptr p;
        MyTcpSocket *socket;
        virtual void run();
    
    signals:
        void sendReceivedFileName(const QString &fileName);
    
    };
    
    #endif // MYTHREAD_H
    
    

    mythread.cpp

    #include "mythread.h"
    #include "mysocket.h"
    #include <QDebug>
    
    MyThread::MyThread(QWidget *parent, qintptr socket) : QThread(parent)
    {
        this->p = socket;
    
        connect(this, SIGNAL(finished()), SLOT(deletLater()));
    }
    
    void MyThread::run()
    {
        MySocket *socket = new MySocket(0, this->p);
        connect(socket, &MySocket::disconnected, this, &MyThread::quit, Qt::DirectConnection);
        connect(socket, &MySocket::sendReceivedFileName, this, &MyThread::sendReceivedFileName);
        this->exec();
    }
    

    mysocket.h

    #ifndef MYSOCKET_H
    #define MYSOCKET_H
    
    #include <QTcpSocket>
    #include <QFile>
    
    
    class MySocket : public QTcpSocket
    {
        Q_OBJECT
    public:
        MySocket(QWidget *parent, qintptr socket);
        //处理新来的链接
    public slots:
        void on_connected();
    public:
        QFile *file;
        QByteArray inBlock, outBlcok;
        int photoCount = 0;
    
        qint64 gotBytes = 0, fileBytes, fileNameSize, bytesReceived;
        qint64 fileSize, sendTotalBytes, bytesToWrite, bytesWritten;
        QString fileName;
        QString receivedMd5;
    
        int socketFlag;
    
        int photoN;
        int currentLocation;
        QStringList fileNameList;
        bool updateVersion;
        QString Tips;
    
        bool firstConnection = false;
    
        void replyMd5(bool boole = true);
    
        void sendFile(bool boole = true);
    
    signals:
        void sendReceivedFileName(const QString &fileName);
    };
    
    #endif // MYSOCKET_H
    

    mysocket.cpp

    #include "mysocket.h"
    #include <QDataStream>
    #include <QCryptographicHash>
    #include <QSettings>
    #include <QMessageBox>
    #include <QDebug>
    
    enum socketFlag{
        md5 = 1,
        versionFlag
    };
    
    MySocket::MySocket(QWidget *parent, qintptr socket) : QTcpSocket(0)
    {
        this->setSocketDescriptor(socket);
    
        connect(this, SIGNAL(readyRead()), this, SLOT(on_connected()));
    
        bytesReceived = 0;
        gotBytes = 0;
        fileBytes = 0;
        fileNameSize = 0;
    
        connect(this, &MySocket::disconnected, []{
            qDebug() << "disconnected";
        });
    }
    
    void MySocket::on_connected()
    {
    //读到数据的操作
        qDebug() << "conn";
    }
    

    客户端

    h文件

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "mytcpsockets.h"
    #include <QTimer>
    
    class QTcpSocket;
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private slots:
        void on_pushButton_clicked();
    
        void on_pushButton_2_clicked();
    
        void on_pushButton_3_clicked();
    
        void on_pushButton_4_clicked();
    
    signals:
        void con(const QString &ip, int port);
        void discon();
    
    private:
        Ui::MainWindow *ui;
    
        QTcpSocket *socket;
    
        QHash<int, QTcpSocket *> m_hash;
    
        MyTcpSockets *m_socket = nullptr;
    
        QTimer tm;
    };
    
    #endif // MAINWINDOW_H
    

    cpp文件

    void MainWindow::on_pushButton_4_clicked()
    {
        //线程发送
        int b = ui->listWidget->count();
        QThread *th = new QThread;
        th->start();
        for (int i = 0; i < b; i++)
        {
            QString fileName = ui->listWidget->item(i)->text();
    
            MySocketTwo *two  = new MySocketTwo(fileName, i);
            connect(this, &MainWindow::con, two, &MySocketTwo::cnt, Qt::QueuedConnection);
    
            two->moveToThread(th);
        }
        emit this->con(ui->lineEdit->text(), 6666);
    
        return ;
    }
    

    mysockettwo.h

    #ifndef MYSOCKETTWO_H
    #define MYSOCKETTWO_H
    
    #include <QTcpSocket>
    #include <QIODevice>
    #include <QHostAddress>
    
    class QFile;
    class MySocketTwo : public QTcpSocket
    {
        Q_OBJECT
    public:
        MySocketTwo(QString &fileName, int n, QObject *parent = 0);
    
        qint64 totalBytes, receivedBytes, sendBytes;
        QByteArray byteArray;
        int number = 0;
        QFile *file;
        QString fileName;
    
    public slots:
        void cnt(const QString &ip, const int &port);
        
    signals:
        void sendProgress(const int &i, const int &n);
        void sendData(const int &i, const QString &str);
    };
    
    #endif // MYSOCKETTWO_H
    

    mysockettwo.cpp

    #include "mysockettwo.h"
    #include <QFile>
    #include <QDataStream>
    #include <QTcpSocket>
    #include <QFileInfo>
    #include <QCryptographicHash>
    
    MySocketTwo::MySocketTwo(QString &fileName, int n, QObject *parent) : QTcpSocket(parent),
        totalBytes(0), receivedBytes(0), sendBytes(0)
    {
    //初始化信号
        connect(this, &MySocketTwo::connected, this, &MySocketTwo::newFile);
    
        this->number = n;//分配序号
        this->fileName = fileName;
    }
    
    
    void MySocketTwo::cnt(const QString &ip, const int &port)
    {
        this->connectToHost(ip, port);
        qDebug() << this->waitForConnected(5000);
        qDebug() << "connect";
    }
    
    void MySocketTwo::newFile()
    {
    //连接上服务器之后的操作
    }
    
    展开全文
  • 服务器与客户端的时间同步

    千次阅读 2018-10-06 14:24:24
    服务器与客户端的时间同步    服务器、客户端全部代码下载:https://download.csdn.net/download/lyhoo163/10703465   一、服务器与客户端的时间同步 我们在编程时,需要让客户端与服务器的时间保存一致...

                                                     服务器与客户端的时间同步

     

                 服务器、客户端全部代码下载:https://download.csdn.net/download/lyhoo163/10703465

               

    一、服务器与客户端的时间同步

    我们在编程时,需要让客户端与服务器的时间保存一致(同步),这样,对于数据的查询和处理很有必要。比如,防止用户修改当前时间,造成数据逻辑混乱,客户端使用的时间应为服务器时间。

    如何处理呢,我们可以使用Delphi Indy组件中的    TIdDayTimeServer和TIdDayTime一对组件。

    TIdDayTimeServer用于服务器端,TIdDayTime用于客户端,二级控件只要参数配置好,随时可以校准二者的时间。

    只要我们在客户端,通过Timer定时,读取服务器时间,并保持一致。

    二、技术准备

    1、在服务器端加入TIdDayTimeServer,大多数使用默认参数。

    (1)IdDayTimeServer1.DefaultPort

    默认端口:1339(通常默认值)

    (2)IdDayTimeServer1.Active

    True,启动IdDayTimeServer。

    False,关闭IdDayTimeServer。

    2、在客户端加入TIdDayTimeServer,大多数使用默认参数。

    (1)IdDayTime1.Host

    服务器IP地址,

    (2) IdDayTime1.Port

    服务器端口:与服务器端一致。

    (3)IdDayTime1.DayTimeStr

    返回时间字符串,格式如下:

    “星期六, 十月 06, 2018 12:26:27-EST”

    这是正常返回的值,通过分析此格式,通过由该字符串,获取相关日期时间的值。

    3、SetLocalTime(SysTime) ,设置本地时间(API)

    4、系统时间参数,TSystemTime类型,用于设置本地时间,它的数据结构如下:

    TSystemTime = record

        wYear: Word;

        wMonth: Word;

        wDayOfWeek: Word;

        wDay: Word;

        wHour: Word;

        wMinute: Word;

        wSecond: Word;

       wMilliseconds: Word;

    end;

    5、分解DayTimeStr获取,标准时间值函数

    CopyDateTime(S)                // 代码参见下文

    三、代码如下:

    1、服务器

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      IdDayTimeServer1.DefaultPort := StrToIntDef(Edit1.Text, strtoint(Edit1.Text));
      IdDayTimeServer1.Active := True;
      Memo1.Lines.Add('服务器启动成功');
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      IdDayTimeServer1.Active := false;
      Memo1.Lines.Add('服务器连接断开!');
    end;
    

    2、客户端

    function TForm1.CopyDateTime(TimeStr:string):String; // CopyDateTime
    var SysTime: TSystemTime;
        tzInfo: Time_Zone_Information;       // 系统参数
        hBias,                               // 小时  偏差
        mBias,                               // 分钟  偏差
        First,Last,Top: Integer;
        S:string;
        i,iYear,iMonth,iDay,iH,iM,iSS:integer;
    
    begin
    
    // 星期六, 十月 06, 2018 12:26:27-EST        格式
    //   1      2    3    4   5 6  7  8          子串序号
      Result:='';
      iYear:=0;
      iMonth:=0;
      iDay:=0;
      iH:=0;
      iM:=0;
      iSS:=0;
      if Length(TimeStr)>30 then
      begin
        First:=0;                                    // 字符首位
        Last:=0;                                     // 字符未位
        Top:=0;                                      // 字符序列号
        for i:=1 to Length(TimeStr) do
        begin
          if (TimeStr[i]=' ') or (TimeStr[i]=',') or (TimeStr[i]=':') or
             (TimeStr[i]='-') or (i=Length(TimeStr)) then  // 断点
          begin
            First:=Last+1;
            Last:=i;
            if i<Length(TimeStr)
              then S:=Copy(TimeStr,First,Last-First)      // 获取一字符
              else S:=Copy(TimeStr,First,Last-First+1);   // 包含最后字符
            S:=Trim(S);                                   // 取消两端空格
            if S<>'' then
            begin
              Top:=Top+1;
    //        showmessage(IntToStr(Top)+':  '+S);
              if Top=2 then                                 // 处理月
              begin
                if (S='一月') or (S='Jan') then iMonth:=1;
                if (S='二月') or (S='Feb') then iMonth:=2;
                if (S='三月') or (S='Mar') then iMonth:=3;
                if (S='四月') or (S='Apr') then iMonth:=4;
                if (S='五月') or (S='May') then iMonth:=5;
                if (S='六月') or (S='Jun') then iMonth:=6;
                if (S='七月') or (S='Jul') then iMonth:=7;
                if (S='八月') or (S='Aug') then iMonth:=8;
                if (S='九月') or (S='Sep') then iMonth:=9;
                if (S='十月') or (S='Oct') then iMonth:=10;
                if (S='十一月') or (S='Nev') then iMonth:=11;
                if (S='十二月') or (S='Dec') then iMonth:=12;
              end;
              if Top=3 then                      // 处理日
                iDay:=StrToInt(S);
              if Top=4 then                      // 处理年
                iYear:=StrToInt(S);
              if Top=5 then                      // 处理时
                iH:=StrToInt(S);
              if Top=6 then                      // 处理分
                iM:=StrToInt(S);
              if Top=7 then                      // 处理秒
                iSS:=StrToInt(S);
            end;
          end;
        end;
      end;
    // 下面分别向SysTime分解字符串的值
      SysTime.wYear:=iYear;
      SysTime.wMonth:=iMonth;
      SysTime.wDay:=iDay;
      SysTime.wHour:=iH;
      SysTime.wMinute:=iM;
      SysTime.wSecond:=iSS;
      SysTime.wMilliseconds:=0;
    // 对获取的SysTime时间值 进行修正
      SysTime.wYear:=SysTime.wYear;                  // 加入日期偏差
      SysTime.wHour:=SysTime.wHour-hBias;            // 加入小时偏差
      SysTime.wMinute:=SysTime.wMinute-mBias;        // 加入小时偏差
      Result:=FormatDateTime('yyyy-mm-dd hh:nn:ss zzz',SystemTimeToDateTime(SysTime));
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
     IdDayTime1.Host := Edit1.Text;                                   // 连接主机
     IdDayTime1.Port := StrToIntDef(Edit2.Text,strtoint(Edit2.Text)); // 端口
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    var sDateTime:string;
        DateTime:TDateTime;
        SystemTime: TSystemTime;
    begin
      DateSeparator:='-';
      ShortDateFormat:='yyyy-MM-dd';
      LongDateFormat:='yyyy''年'',MM''月'',dd''日''';
      TimeSeparator:=':';
    
      sDateTime:=IdDayTime1.DayTimeStr;
      sDateTime:=CopyDateTime(sDateTime);
      Edit4.Text:=sDateTime;
      DateTime:=StrToDateTime(SDateTime);            // 获得时间(TDateTime格式)
      DateTimeToSystemTime(DateTime,systemtime);     // TDateTime格式转化TSystemTime
      SetLocalTime(SystemTime);                      // 设置系统时间
      GetLocalTime(SystemTime);                      // 读取系统时间
      DateTime:=SystemTimeToDateTime(systemtime);    // TSystemTime格式转化TDateTime
      Edit5.Text:=DateTimetoStr(DateTime);
    end;
    
    
    procedure TForm1.Timer1Timer(Sender: TObject); // 定时同步 
    var sDateTime:string;
        DateTime:TDateTime;
        SystemTime: TSystemTime;
    
    begin
      sDateTime:=IdDayTime1.DayTimeStr;
      sDateTime:=CopyDateTime(sDateTime);
      DateTime:=StrToDateTime(SDateTime);          // 获得时间(TDateTime格式)
      DateTimeToSystemTime(DateTime,systemtime);   // TDateTime格式转化TSystemTime格式
      SetLocalTime(SystemTime);                    // 设置系统时间
      StatusBar1.Panels[1].Text:='校正时间:'+sDateTime;
    end;
    
    procedure TForm1.CheckBox1Click(Sender: TObject);
    begin
      if CheckBox1.Checked then
      begin
        Button1Click(Sender);
        Timer1.Enabled:=True;
      end
      else
        Timer1.Enabled:=False;
    end;
    
    

     

    展开全文
  • Python 绝技 —— UDP 服务器与客户端

    千次阅读 2018-06-19 19:14:19
    i春秋作家:wasrehpic0x00 前言在上一篇文章「Python 绝技 —— TCP 服务器与客户端」中,介绍了传输层的核心协议 TCP ,并运用 Python 脚本的 socket 模块演示了 TCP 服务器与客户端的通信过程。本篇将按照同样的...

    i春秋作家:wasrehpic


    0x00 前言

    在上一篇文章「Python 绝技 —— TCP 服务器与客户端」中,介绍了传输层的核心协议 TCP ,并运用 Python 脚本的 socket 模块演示了 TCP 服务器与客户端的通信过程。

    本篇将按照同样的套路,先介绍传输层的另一个核心协议 UDP,再比较 TCP 与 UDP 的特点,最后借助 Python 脚本演示 UDP 服务器与客户端的通信过程。

    0x01 UDP 协议

    UDP(User Datagram Protocol,用户数据报协议)是一种无连接、不可靠、基于数据报的传输层通信协议。

    • UDP 的通信过程与 TCP 相比较为简单,不需要复杂的三次握手与四次挥手,体现了无连接
    • UDP 传输速度比 TCP 快,但容易丢包、数据到达顺序无保证、缺乏拥塞控制、秉承尽最大努力交付的原则,体现了不可靠
    • UDP 的无连接与不可靠特性注定无法采用字节流的通信模式,由协议名中的「Datagram」与 socket 类型中的「SOCK_DGRAM」即可体现它基于数据报的通信模式。

    为了更直观地比较 TCP 与 UDP 的异同,笔者将其整理成以下表格:

     TCPUDP
    连接模式面向连接(单点通信)无连接(多点通信)
    传输可靠性可靠不可靠
    通信模式基于字节流基于数据报
    报头结构复杂(至少20字节)简单(8字节)
    传输速度
    资源需求
    到达顺序保证不保证
    流量控制
    拥塞控制
    应用场合大量数据传输少量数据传输
    支持的应用层协议Telnet、FTP、SMTP、HTTPDNS、DHCP、TFTP、SNMP

    0x02 Network Socket

    Network Socket(网络套接字)是计算机网络中进程间通信的数据流端点,广义上也代表操作系统提供的一种进程间通信机制。

    进程间通信(Inter-Process Communication,IPC)的根本前提是能够唯一标示每个进程。在本地主机的进程间通信中,可以用 PID(进程 ID)唯一标示每个进程,但 PID 只在本地唯一,在网络中不同主机的 PID 则可能发生冲突,因此采用「IP 地址 + 传输层协议 + 端口号」的方式唯一标示网络中的一个进程。

    小贴士:网络层的 IP 地址可以唯一标示主机,传输层的 TCP/UDP 协议和端口号可以唯一标示该主机的一个进程。注意,同一主机中 TCP 协议与 UDP 协议的可以使用相同的端口号。

    所有支持网络通信的编程语言都各自提供了一套 socket API,下面以 Python 3 为例,讲解服务器与客户端建立 UDP 通信连接的交互过程:

    udp_socket_python

    可见,UDP 的通信过程比 TCP 简单许多,服务器少了监听与接受连接的过程,而客户端也少了请求连接的过程。客户端只需要知道服务器的地址,直接向其发送数据即可,而服务器也敞开大门,接收任何发往自家地址的数据。

    小贴士:由于 UDP 采用无连接模式,可知 UDP 服务器在接收到客户端发来的数据之前,是不知道客户端的地址的,因此必须是客户端先发送数据,服务器后响应数据。而 TCP 则不同,TCP 服务器接受了客户端的连接后,既可以先向客户端发送数据,也可以等待客户端发送数据后再响应。

    0x03 UDP 服务器

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind(("127.0.0.1", 6000))
    print("UDP bound on port 6000...")
    
    while True:
        data, addr = s.recvfrom(1024)
        print("Receive from %s:%s" % addr)
        if data == b"exit":
            s.sendto(b"Good bye!\n", addr)
            continue
        s.sendto(b"Hello %s!\n" % data, addr)
    • Line 5:创建 socket 对象,第一个参数为 socket.AF_INET,代表采用 IPv4 协议用于网络通信,第二个参数为 socket.SOCK_DGRAM,代表采用 UDP 协议用于无连接的网络通信。
    • Line 6:向 socket 对象绑定服务器主机地址 ("127.0.0.1", 6000),即本地主机的 UDP 6000 端口。
    • Line 9:进入与客户端交互数据的循环阶段。
    • Line 10:接收客户端发来的数据,包括 bytes 对象 data,以及客户端的 IP 地址和端口号 addr,其中 addr 为二元组 (host, port)。
    • Line 11:打印接收信息,表示从地址为 addr 的客户端接收到数据。
    • Line 12:若 bytes 对象为 b"exit",则向地址为 addr 的客户端发送结束响应信息 b"Good bye!\n"。发送完毕后,继续等待其他 UDP 客户端发来数据。
    • Line 15:若 bytes 对象不为 b"exit",则向地址为 addr 的客户端发送问候响应信息 b"Hello %s!\n",其中 %s是客户端发来的 bytes 对象。发送完毕后,继续等待任意 UDP 客户端发来数据。

    与 TCP 服务器相比,UDP 服务器不必使用多线程,因为它无需为每个通信过程创建独立连接,而是采用「即收即发」的模式,又一次体现了 UDP 的无连接特性。

    0x04 UDP 客户端

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    addr = ("127.0.0.1", 6000)
    
    while True:
        data = input("Please input your name: ")
        if not data:
            continue
        s.sendto(data.encode(), addr)
        response, addr = s.recvfrom(1024)
        print(response.decode())
        if data == "exit":
            print("Session is over from the server %s:%s\n" % addr)
            break
    
    s.close()
    • Line 5:创建 socket 对象,第一个参数为 socket.AF_INET,代表采用 IPv4 协议用于网络通信,第二个参数为 socket.SOCK_DGRAM,代表采用 UDP 协议用于无连接的网络通信。
    • Line 6:初始化 UDP 服务器的地址 ("127.0.0.1", 6000),即本地主机的 UDP 6000 端口。
    • Line 8:进入与服务器交互数据的循环阶段。
    • Line 9:要求用户输入名字。
    • Line 10:当用户的输入为空时,则重新开始循环,要求用户重新输入。
    • Line 12:当用户的输入非空时,则将字符串转换为 bytes 对象后,发送至地址为 ("127.0.0.1", 6000) 的 UDP 服务器。
    • Line 13:接收服务器的响应数据,包括 bytes 对象 response,以及服务器的 IP 地址和端口号 addr,其中 addr 为二元组 (host, port)。
    • Line 14:将响应的 bytes 对象 response 转换为字符串后打印输出。
    • Line 15:当用户的输入为 "exit" 时,则打印会话结束信息,终止与服务器交互数据的循环阶段,即将关闭套接字。
    • Line 19:关闭套接字,不再向服务器发送数据。

    0x05 UDP 进程间通信

    将 UDP 服务器与客户端的脚本分别命名为 udp_server.py 与 udp_client.py,然后存至桌面,笔者将在 Windows 10 系统下用 PowerShell 进行演示。

    小贴士:读者进行复现时,要确保本机已安装 Python 3,注意笔者已将默认的启动路径名 python 改为了 python3

    单服务器 VS 多客户端

    one_server_vs_multiple_clients

    1. 在其中一个 PowerShell 中运行命令 python3 ./udp_server.py,服务器绑定本地主机的 UDP 6000 端口,并打印信息 UDP bound on port 6000...,等待客户端发来数据;
    2. 在另两个 PowerShell 中分别运行命令 python3 ./udp_client.py,并向服务器发送字符串 Client1Client2
    3. 服务器打印接收信息,表示分别从 UDP 63643、63644端口接收到数据,并分别向客户端发送问候响应信息;
    4. 客户端 Client1 发送空字符串,则被要求重新输入;
    5. 客户端 Client2 先发送字符串 Alice,得到服务器的问候响应信息,再发送字符串 exit,得到服务器的结束响应信息,最后打印会话结束信息,终止与服务器的数据交互;
    6. 客户端 Client1 发送字符串 exit,得到服务器的结束响应信息,并打印会话结束信息,终止与服务器的数据交互;
    7. 服务器按照以上客户端的数据发送顺序打印接收信息,并继续等待任意 UDP 客户端发来数据。

    0x06 Python API Reference

    socket 模块

    本节介绍上述代码中用到的内建模块 socket,是 Python 网络编程的核心模块。

    socket() 函数

    socket() 函数用于创建网络通信中的套接字对象。函数原型如下:

    socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
    • family 参数代表地址族(Address Family),默认值为 AF_INET,用于 IPv4 网络通信,常用的还有 AF_INET6,用于 IPv6 网络通信。family 参数的可选值取决于本机操作系统。
    • type 参数代表套接字的类型,默认值为 SOCK_STREAM,用于 TCP 协议(面向连接)的网络通信,常用的还有 SOCK_DGRAM,用于 UDP 协议(无连接)的网络通信。
    • proto 参数代表套接字的协议,默认值为 0,一般忽略该参数,除非 family 参数为 AF_CAN,则 proto 参数需设置为 CAN_RAW 或 CAN_BCM
    • fileno 参数代表套接字的文件描述符,默认值为 None,若设置了该参数,则其他三个参数将会被忽略。

    创建完套接字对象后,需使用对象的内置函数完成网络通信过程。注意,以下函数原型中的「socket」是指 socket 对象,而不是上述的 socket 模块。

    bind() 函数

    bind() 函数用于向套接字对象绑定 IP 地址与端口号。注意,套接字对象必须未被绑定,并且端口号未被占用,否则会报错。函数原型如下:

    socket.bind(address)
    • address 参数代表套接字要绑定的地址,其格式取决于套接字的 family 参数。若 family 参数为 AF_INET,则 address 参数表示为二元组 (host, port),其中 host 是用字符串表示的主机地址,port 是用整型表示的端口号。

    sendto() 函数

    sendto() 函数用于向远程套接字对象发送数据。注意,该函数用于 UDP 进程间的无连接通信,远程套接字的地址在参数中指定,因此使用前不需要先与远程套接字连接。相对地,TCP 进程间面向连接的通信过程需要用 send() 函数。函数原型如下:

    socket.sendto(bytes[, flags], address)
    • bytes 参数代表即将发送的 bytes 对象数据。例如,对于字符串 "hello world!" 而言,需要用 encode() 函数转换为 bytes 对象 b"hello world!" 才能进行网络传输。
    • flags 可选参数用于设置 sendto() 函数的特殊功能,默认值为 0,也可由一个或多个预定义值组成,用位或操作符 | 隔开。详情可参考 Unix 函数手册中的 sendto(2)flags 参数的常见取值有 MSG_OOB、MSG_EOR、MSG_DONTROUTE 等。
    • address 参数代表远程套接字的地址,其格式取决于套接字的 family 参数。若 family 参数为 AF_INET,则 address 参数表示为二元组 (host, port),其中 host 是用字符串表示的主机地址,port 是用整型表示的端口号。

    sendto() 函数的返回值是发送数据的字节数。

    recvfrom() 函数

    recvfrom() 函数用于从远程套接字对象接收数据。注意,与 sendto() 函数不同,recvfrom() 函数既可用于 UDP 进程间通信,也能用于 TCP 进程间通信。函数原型如下:

    socket.recvfrom(bufsize[, flags])
    • bufsize 参数代表套接字可接收数据的最大字节数。注意,为了使硬件设备与网络传输更好地匹配,bufsize 参数的值最好设置为 2 的幂次方,例如 4096
    • flags 可选参数用于设置 recv() 函数的特殊功能,默认值为 0,也可由一个或多个预定义值组成,用位或操作符 |隔开。详情可参考 Unix 函数手册中的 recvfrom(2)flags 参数的常见取值有 MSG_OOB、MSG_PEEK、MSG_WAITALL 等。

    recvfrom() 函数的返回值是二元组 (bytes, address),其中 bytes 是接收到的 bytes 对象数据,address 是发送方的 IP 地址与端口号,用二元组 (host, port) 表示。注意,recv() 函数的返回值只有 bytes 对象数据。

    close() 函数

    close() 函数用于关闭本地套接字对象,释放与该套接字连接的所有资源。

    socket.close()

    0x07 总结

    本文介绍了 UDP 协议的基础知识,并与 TCP 协议进行对比,再用 Python 3 实现并演示了 UDP 服务器与客户端的通信过程,最后将脚本中涉及到的 Python API 做成了的参考索引,有助于读者理解实现过程。

    感谢各位的阅读,笔者水平有限,若有不足或错误之处请谅解并告知,希望自己对 TCP 和 UDP 的浅薄理解,能帮助读者更好地理解传输层协议。

    本文的相关参考请移步至:

    TCP和UDP的最完整的区别
    TCP和UDP之间的区别

    UDP编程 - 廖雪峰的官方网站

    展开全文
  • Ubuntu配置NFS服务器与客户端

    千次阅读 2016-05-30 18:05:02
    Ubuntu配置NFS服务器与客户端

    环境:Ubuntu16.04 64位 配置NFS服务器。

    安装NFS服务器端:

    apt-get install nfs-kernel-server
    下载完创建NFS的文件夹

    mkdir /opt/nfs_folder
    配置服务器端配置:

    vi /etc/exports
    在最后一行写入
    /opt/nfs_folder *(rw,sync,no_root_squash,no_subtree_check)
    
    //
    *:允许所有的网段访问,也可以使用具体的IP
    rw:挂接此目录的客户端对该共享目录具有读写权限
    sync:资料同步写入内存和硬盘
    no_root_squash:root用户具有对根目录的完全管理访问权限。
    no_subtree_check:不检查父目录的权限
    // 重启rpcbind 服务。nfs是一个RPC程序,使用它前,需要映射好端口,通过rpcbind 设定。
    /etc/init.d/rpcbind restart
    
    
    /etc/init.d/nfs-kernel-server restart //重启nfs服务
    服务器端就配置完成了。

    客户端

    apt-get install nfs-common //下载nfs命令
    挂载服务器共享文件夹到本地

    mount -t nfs 192.168.30.129:/opt/nfs_folder /opt/myfolder/
    就完成了,这时候你在本地/opt/myfolder/下创建test.php文件,在服务器/opt/nfs/nfs_folder/下看到test.php










    展开全文
  • 使用nodejs实现web服务器与客户端的交互 使用nodejs实现web服务器与客户端的交互 1.实验目的: 使用SOAP等web service 协议,完成一个WEB服务的服务器与客户端的交互。 2.实验内容: 使用nodejs实现web服务器与...
  • Java 服务器与客户端的简单连接

    千次阅读 2019-03-09 11:53:50
    今天刚学了一点socket,写了一个服务器与客户端的简单连接 利用的主要就是socket建立连接,发送数据 以下几个方法要注意: Socket(InetAddress address, int port); //创建一个流套接字并将其连接到指定 IP 地址...
  • 一个简单的服务器与客户端程序

    千次阅读 2016-11-19 21:25:19
    利用linux系统IO、socket,实现服务器与客户端直接的通信
  • HLS协议之服务器与客户端之前的交互流程
  • C# Socket简单例子(服务器与客户端通信)

    千次下载 热门讨论 2011-07-24 15:46:15
    这是两个很简单的程序(服务端、客户端) 达成两端之间的通信例子。 Socket
  • WebSocket实现服务器与客户端握手 自学的WebSocket途中遇到很多坑,希望需要使用的朋友可以少走弯路, 使用的环境:tomcat7.0,mysql,springMvc,spring,Mybatis 主要使用2个jar包 这2个jar包在tomcat7的 lib文件夹...
  • 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。... 写在前面 ...对于Java NIO已经学习了一段时间了,周末...下面的实践是:服务器与客户端都采用NIO的方
  • 服务器与客户端数据交互 服务器返回到客户端的就是一个字符串,客户端若希望拿到一个对象类型,则需要一种规则来存储字符串。 所以js中出现了json语法来定义对象格式。 服务器将数据序列化为json格式字符返回给...
  • TCP实现服务器与客户端的连接

    千次阅读 2019-12-28 00:51:16
    实现服务器客户端的通信,有以下需求: 服务器: (1)服务器需要接收客户端的聊天请求,为了让客户端找到自己,必须要有一个确定的 ip地址 + 端口号 来标识自己。 (2)服务器接收到客户端发来的消息,需要给...
  • TCP服务器与客户端

    千次阅读 2018-07-13 23:53:34
    1、生活中的“打电话”实例(TCP) (1)买个手机 (2)插上手机卡 (3)设计手机为正常接听状态(即能够响铃) (4)静静的等着别人拨打 (5)挂断手机,结束通话2、tcp服务器 (1)socket创建一个套接字 ...
  • Win32写的斗地主游戏服务器与客户端
  • SignalR实现服务器与客户端的实时通信 百度百科给它的定义 实现实时通信。什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端可以互相通知消息及调用方法,当然这是实时操作的。 WebSockets...
  • Android BLE与终端通信(四)——实现服务器与客户端即时通讯功能 前面几篇一直在讲一些基础,其实说实话,蓝牙主要为多的还是一些概念性的东西,当你把概念都熟悉了之后,你会很简单的就可以实现一些逻辑,主要是...
  • python socket之tcp服务器与客户端demo

    千次阅读 2015-06-24 12:56:00
    python socket之tcp服务器与客户端demo 作者:vpoet 日期:夏季 server: # -*- coding: cp936 -*- ''' 建立一个python server,监听指定端口, 如果该端口被远程连接访问,则获取远程连接,然后接收数据,...
  • 本小游戏是在Linux下实现的(因为我不会Windows网络编程),这次实现的仅仅是服务器与客户端之间进行互动,彼此只要互相发送下点的坐标就ok,用结构体存放坐标,各自收到坐标后进行下子,以及判断结果。 本篇文章里只...
  • 本节内容是代码实现服务器与客户端完整连接过程。整体把控netty的工作流程。我们先不要被某个类,某个api的封装深入挖掘,这样你会踩很多坑,陷入进去而拔不出来,后面我会一一讲解,源码剖析工作原理。这就是我个人...
  • 网络编程服务器与客户端分析

    千次阅读 2019-03-14 21:39:56
    又叫主从式架构,简称C/S结构,是一种网络架构,它把客户端 (Client) (通常是一个采用图形用户界面的程序)与服务器 (Server) 区分开来。每一个客户端软件的实例都可以向一个服务器或应用程序服务器发出请求。有很...
  • WSAAsyncselect 模型中,服务器与客户端消息的收发 新建一�?/span>MFC对话框程�?/font> 服务器与客户端的对话框基本一致,以服务器为例�?/span>   将左右两�?/span>编辑�?/span>设置�?/span>多行...
  • C# Socket简单例子(服务器与客户端通信) http://blog.csdn.net/andrew_wx/article/details/6629721 添加一点自己的东西,如果要做服务器测试,写一个上面教程的代码,开一个服务端,几百个客户端程序,就...
  • 自己编写了 个 辅助 客户端需绑定后连接到服务器服务器主要是 使用权限和统计用。问服务器怎设置外网让客户端运作就 连接到 服务器服务器要时时接收客户端运作的 数据,用路由映射服务器内网IP就 可以 了吗 还 ...
  • 服务器与客户端理论基础知识

    千次阅读 2017-01-03 23:26:00
    服务器 1. 服务器类型 2. 服务器软件 3. HTTP服务器 客户端
  • Linux系统编程(32)—— socket编程之TCP服务器与客户端TCP协议的客户端/服务器程序的一般流程 服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态,客户端调用socket...
  • TCP协议---服务器与客户端状态转换图

    千次阅读 多人点赞 2011-09-22 15:28:10
    TCP服务器与客户端通信过程的状态转换图   理解状态转换是使用netstat命令来诊断网络问题的基础,也是理解比如调用connect,accept和close函数的过程的关键所在。 下面是TCP中的一种连接过程: 客户端发起连接...
  • linux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程 server.c #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <netdb.h> #include <...
  • Ubuntu之NTP服务器与客户端时间同步

    千次阅读 2019-05-31 11:11:35
    在局域网环境下,嵌入式终端的时间容易出现错乱,因此,设置一个时间同步服务器,让局域网内的客户端自动与服务器时间同步 1修改时区 如果是有一块新板子,时区设置默认使用UTC国际标准时区,我们需要修改为CST...
  • 各位大神,一个服务器连接多个客户端,现在我想判断某一个已经定义了的CSocket对象是否与客户端已经绑定,该怎么判断?

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 83,015
精华内容 33,206
关键字:

服务器与客户端