精华内容
下载资源
问答
  • C语言通过socket编程实现TCP通信

    万次阅读 多人点赞 2018-01-02 13:46:27
    服务端客户端通信例子:socket tcp 通信1,socket tcp通信2,udp使用讲解,socket udp通信例子 1. TCP/IP协议 叫做传输控制/网际协议,又叫网络通信协议。实际上,它包含上百个功能的协议,如ICMP(互联网控制信息...

    目录

    1.  TCP/IP协议

    2.套接字(socket):

    3.下面给出server和client的两个例子

    服务端:

    客户端:


    服务端客户端通信例子:socket tcp 通信1socket tcp通信2udp使用讲解socket udp通信例子

    1.  TCP/IP协议

    叫做传输控制/网际协议,又叫网络通信协议。实际上,它包含上百个功能的协议,如ICMP(互联网控制信息协议)、FTP(文件传输协议)、UDP(用户数据包协议)、ARP(地址解析协议)等。TCP负责发现传输的问题,一旦有问题就会发出重传信号,直到所有数据安全正确的传输到目的地。

    2.套接字(socket)

        在网络中用来描述计算机中不同程序与其他计算机程序的通信方式。socket其实是一种特殊的IO接口,也是一种文件描述符。

    套接字分为三类:

        流式socket(SOCK_STREAM):流式套接字提供可靠、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性。

        数据报socket(SOCK_DGRAM):数据报套接字定义了一种无连接的服务,数据通过相互独立的保温进行传输,是无序的,并且不保证是可靠、无差错的。它使用的数据报协议是UDP。

        原始socket:原始套接字允许对底层协议如IP或ICMP进行直接访问,它功能强大但使用复杂,主要用于一些协议的开发。

    套接字由三个参数构成:IP地址,端口号,传输层协议。这三个参数用以区分不同应用程序进程间的网络通信与连接。

    套接字的数据结构:C语言进行套接字编程时,常会使用到sockaddr数据类型和sockaddr_in数据类型,用于保存套接字信息。

    两种结构体分别表示如下:

    struct sockaddr {
        //地址族,2字节
        unsigned short sa_family;
    
        //存放地址和端口,14字节
        char sa_data[14];
    }
    
    
    struct sockaddr_in {
        //地址族
        short int sin_family;
    
        //端口号(使用网络字节序)
        unsigned short int sin_port;
    
        //地址
        struct in_addr sin_addr;
    
        //8字节数组,全为0,该字节数组的作用只是为了让两种数据结构大小相同而保留的空字节
        unsigned char sin_zero[8]
    }
    

    对于sockaddr,大部分的情况下只是用于bind,connect,recvfrom,sendto等函数的参数,指明地址信息,在一般编程中,并不对此结构体直接操作。而用sockaddr_in来替。

    两种数据结构中,地址族都占2个字节,

    常见的地址族有:AF_INET,AF_INET6AF_LOCAL。

    这里要注意字节序的问题,最好使用以下函数来对端口和地址进行处理:

    1.  uint16_t htons(uint16_t host16bit) 把16位值从主机字节序转到网络字节序

        uint32_t htonl(uint32_t host32bit)  把32位值从主机字节序转到网络字节序

    2.  uint16_t ntohs(uint16_t net16bit) 把16位值从网络字节序转到主机字节序

        uint32_t ntohs(uint32_t net32bit)  把32位值从网络字节序转到主机字节序

    使用socket进行TCP通信时,经常使用的函数有:

     

    3.下面给出serverclient的两个例子

     

    更详细的例子

    服务端:

    /*socket tcp服务器端*/

    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #define SERVER_PORT 6666
    
    /*
    监听后,一直处于accept阻塞状态,
    直到有客户端连接,
    当客户端如数quit后,断开与客户端的连接
    */
    int main() {
    
        //调用socket函数返回的文件描述符
    
        int serverSocket;
    
        //声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器
    
        struct sockaddr_in server_addr;
    
        struct sockaddr_in clientAddr;
    
        int addr_len = sizeof(clientAddr);
    
        int client;
    
        char buffer[200];
    
        int iDataNum;
    
        //socket函数,失败返回-1
        //int socket(int domain, int type, int protocol);
        //第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
        //第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM
        //第三个参数设置为0
        if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            perror("socket");
            return 1;
        }
    
        bzero(&server_addr, sizeof(server_addr));
    
        //初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(SERVER_PORT);
    
        //ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
        //对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
        //bind三个参数:服务器端的套接字的文件描述符,
    
        if (bind(serverSocket, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
            perror("connect");
            return 1;
        }
    
        //设置服务器上的socket为监听状态
        if (listen(serverSocket, 5) < 0) {
            perror("listen");
            return 1;
    
        }
    
        while (1) {
    
            printf("监听端口: %d\n", SERVER_PORT);
    
            //调用accept函数后,会进入阻塞状态
            //accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
            //serverSocket和client。
            //serverSocket仍然继续在监听状态,client则负责接收和发送数据
            //clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
            //addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
            //传出的是客户端地址结构体的实际长度。
            //出错返回-1
            client = accept(serverSocket, (struct sockaddr *) &clientAddr, (socklen_t *) &addr_len);
    
            if (client < 0) {
                perror("accept");
                continue;
    
            }
    
            printf("等待消息...\n");
            //inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
            //表达式:char *inet_ntoa (struct in_addr);
            printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
            printf("Port is %d\n", htons(clientAddr.sin_port));
    
            while (1) {
                printf("读取消息:");
                buffer[0] = '\0';
                iDataNum = recv(client, buffer, 1024, 0);
                if (iDataNum < 0) {
                    perror("recv null");
                    continue;
                }
    
                buffer[iDataNum] = '\0';
                if (strcmp(buffer, "quit") == 0)
                    break;
                printf("%s\n", buffer);
                printf("发送消息:");
    
                scanf("%s", buffer);
                printf("\n");
                send(client, buffer, strlen(buffer), 0);
    
                if (strcmp(buffer, "quit") == 0)
                    break;
            }
    
        }
    
        close(serverSocket);
        return 0;
    }

    客户端:

    /*socket tcp客户端*/

    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    #define SERVER_PORT 6666
    
    /*
    连接到服务器后,会不停循环,等待输入,
    输入quit后,断开与服务器的连接
    */
    
    int main() {
    
        //客户端只需要一个套接字文件描述符,用于和服务器通信
        int clientSocket;
    
        //描述服务器的socket
        struct sockaddr_in serverAddr;
        char sendbuf[200];
        char recvbuf[200];
        int iDataNum;
    
        if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            perror("socket");
            return 1;
    
        }
    
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(SERVER_PORT);
    
        //指定服务器端的ip,本地测试:127.0.0.1
        //inet_addr()函数,将点分十进制IP转换成网络字节序IP
        serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        if (connect(clientSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) {
    
            perror("connect");
    
            return 1;
    
        }
    
        printf("连接到主机...\n");
        while (true) {
            printf("发送消息:");
            scanf("%s", sendbuf);
            printf("\n");
            send(clientSocket, sendbuf, strlen(sendbuf), 0);
            if (strcmp(sendbuf, "quit") == 0)
                break;
    
            printf("读取消息:");
            recvbuf[0] = '\0';
            iDataNum = recv(clientSocket, recvbuf, 200, 0);
            recvbuf[iDataNum] = '\0';
            printf("%s\n", recvbuf);
    
        }
    
        close(clientSocket);
        return 0;
    
    }
    
    

     

    展开全文
  • QT5实现简单的TCP通信

    万次阅读 多人点赞 2017-04-11 00:43:20
    这段时间用到了QT的TCP通信,做了初步的学习与尝试,编写了一个客户端和服务器基于窗口通信的小例程。 使用QT的网络套接字需要.pro文件中加入一句: QT += network 一、客户端 1、客户端的代码比服务器稍简单,...

    这段时间用到了QT的TCP通信,做了初步的学习与尝试,编写了一个客户端和服务器基于窗口通信的小例程。

    使用QT的网络套接字需要.pro文件中加入一句:

    QT       += network

    一、客户端

    1、客户端的代码比服务器稍简单,总的来说,使用QT中的QTcpSocket类与服务器进行通信只需要以下5步:

    (1)创建QTcpSocket套接字对象

    socket = new QTcpSocket();

    (2)使用这个对象连接服务器

    socket->connectToHost(IP, port);

    (3)使用write函数向服务器发送数据

    socket->write(data);

    (4)当socket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据

    QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
    
    void MainWindow::socket_Read_Data()
    {
        QByteArray buffer;
        //读取缓冲区数据
        buffer = socket->readAll();
    }

    (5)断开与服务器的连接(关于close()和disconnectFromHost()的区别,可以按F1看帮助)

    socket->disconnectFromHost();

    2、以下是客户端的例程

    首先是mainwindow.h文件:

    //mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QTcpSocket>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private slots:
    
        void on_pushButton_Connect_clicked();
    
        void on_pushButton_Send_clicked();
    
        void socket_Read_Data();
    
        void socket_Disconnected();
    
    private:
        Ui::MainWindow *ui;
        QTcpSocket *socket;
    };
    
    #endif // MAINWINDOW_H
    

    然后是mainwindow.cpp文件:

    //mainwindow.cpp
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        socket = new QTcpSocket();
    
        //连接信号槽
        QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
        QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);
    
        ui->pushButton_Send->setEnabled(false);
        ui->lineEdit_IP->setText("127.0.0.1");
        ui->lineEdit_Port->setText("8765");
    
    }
    
    MainWindow::~MainWindow()
    {
        delete this->socket;
        delete ui;
    }
    
    void MainWindow::on_pushButton_Connect_clicked()
    {
        if(ui->pushButton_Connect->text() == tr("连接"))
        {
            QString IP;
            int port;
    
            //获取IP地址
            IP = ui->lineEdit_IP->text();
            //获取端口号
            port = ui->lineEdit_Port->text().toInt();
    
            //取消已有的连接
            socket->abort();
            //连接服务器
            socket->connectToHost(IP, port);
    
            //等待连接成功
            if(!socket->waitForConnected(30000))
            {
                qDebug() << "Connection failed!";
                return;
            }
            qDebug() << "Connect successfully!";
    
            //发送按键使能
            ui->pushButton_Send->setEnabled(true);
            //修改按键文字
            ui->pushButton_Connect->setText("断开连接");
        }
        else
        {
            //断开连接
            socket->disconnectFromHost();
            //修改按键文字
            ui->pushButton_Connect->setText("连接");
            ui->pushButton_Send->setEnabled(false);
        }
    }
    
    void MainWindow::on_pushButton_Send_clicked()
    {
        qDebug() << "Send: " << ui->textEdit_Send->toPlainText();
         //获取文本框内容并以ASCII码形式发送
        socket->write(ui->textEdit_Send->toPlainText().toLatin1());
        socket->flush();
    }
    
    void MainWindow::socket_Read_Data()
    {
        QByteArray buffer;
        //读取缓冲区数据
        buffer = socket->readAll();
        if(!buffer.isEmpty())
        {
            QString str = ui->textEdit_Recv->toPlainText();
            str+=tr(buffer);
            //刷新显示
            ui->textEdit_Recv->setText(str);
        }
    }
    
    void MainWindow::socket_Disconnected()
    {
        //发送按键失能
        ui->pushButton_Send->setEnabled(false);
        //修改按键文字
        ui->pushButton_Connect->setText("连接");
        qDebug() << "Disconnected!";
    }

    最后是ui的设计:

    二、服务器

    1、服务器除了使用到了QTcpSocket类,还需要用到QTcpSever类。即便如此,也只是比客户端复杂一点点,用到了6个步骤:

    (1)创建QTcpSever对象

    server = new QTcpServer();

    (2)侦听一个端口,使得客户端可以使用这个端口访问服务器

    server->listen(QHostAddress::Any, port);

    (3)当服务器被客户端访问时,会发出newConnection()信号,因此为该信号添加槽函数,并用一个QTcpSocket对象接受客户端访问

    connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect);
    
    void MainWindow::server_New_Connect()
    {
        //获取客户端连接
        socket = server->nextPendingConnection();
    }

    (4)使用socket的write函数向客户端发送数据

    socket->write(data);

    (5)当socket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据

    QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
    
    void MainWindow::socket_Read_Data()
    {
        QByteArray buffer;
        //读取缓冲区数据
        buffer = socket->readAll();
    }

    (6)取消侦听

    server->close();

    2、以下是服务器的例程

    首先是mainwindow.h文件:

    //mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QTcpServer>
    #include <QTcpSocket>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private slots:
        void on_pushButton_Listen_clicked();
    
        void on_pushButton_Send_clicked();
    
        void server_New_Connect();
    
        void socket_Read_Data();
    
        void socket_Disconnected();
    
    private:
        Ui::MainWindow *ui;
        QTcpServer* server;
        QTcpSocket* socket;
    };
    
    #endif // MAINWINDOW_H

    然后是mainwindow.cpp文件:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        ui->lineEdit_Port->setText("8765");
        ui->pushButton_Send->setEnabled(false);
    
        server = new QTcpServer();
    
        //连接信号槽
        connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect);
    }
    
    MainWindow::~MainWindow()
    {
        server->close();
        server->deleteLater();
        delete ui;
    }
    
    void MainWindow::on_pushButton_Listen_clicked()
    {
        if(ui->pushButton_Listen->text() == tr("侦听"))
        {
            //从输入框获取端口号
            int port = ui->lineEdit_Port->text().toInt();
    
            //监听指定的端口
            if(!server->listen(QHostAddress::Any, port))
            {
                //若出错,则输出错误信息
                qDebug()<<server->errorString();
                return;
            }
            //修改按键文字
            ui->pushButton_Listen->setText("取消侦听");
            qDebug()<< "Listen succeessfully!";
        }
        else
        {
    /*
            //如果正在连接(点击侦听后立即取消侦听,若socket没有指定对象会有异常,应修正——2017.9.30)
            if(socket->state() == QAbstractSocket::ConnectedState)
            {
                //关闭连接
                socket->disconnectFromHost();
            }
    */
            socket->abort();
            //取消侦听
            server->close();
            //修改按键文字
            ui->pushButton_Listen->setText("侦听");
            //发送按键失能
            ui->pushButton_Send->setEnabled(false);
        }
    
    }
    
    void MainWindow::on_pushButton_Send_clicked()
    {
        qDebug() << "Send: " << ui->textEdit_Send->toPlainText();
        //获取文本框内容并以ASCII码形式发送
        socket->write(ui->textEdit_Send->toPlainText().toLatin1());
        socket->flush();
    }
    
    void MainWindow::server_New_Connect()
    {
        //获取客户端连接
        socket = server->nextPendingConnection();
        //连接QTcpSocket的信号槽,以读取新数据
        QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
        QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);
        //发送按键使能
        ui->pushButton_Send->setEnabled(true);
    
        qDebug() << "A Client connect!";
    }
    
    void MainWindow::socket_Read_Data()
    {
        QByteArray buffer;
        //读取缓冲区数据
        buffer = socket->readAll();
        if(!buffer.isEmpty())
        {
            QString str = ui->textEdit_Recv->toPlainText();
            str+=tr(buffer);
            //刷新显示
            ui->textEdit_Recv->setText(str);
        }
    }
    
    void MainWindow::socket_Disconnected()
    {
        //发送按键失能
        ui->pushButton_Send->setEnabled(false);
        qDebug() << "Disconnected!";
    }

    最后是ui的设计:

    三、运行结果

    附上两个工程的下载链接:http://download.csdn.net/detail/u014695839/9810107

    以上是根据这几天学习总结出的基于QT5的TCP通信的简单实现,如有错误希望能指出,欢迎各位多多交流!

     

    展开全文
  • TCP通信

    千次阅读 2019-03-10 17:14:20
    1、提供面向连接的可靠的...2、一个TCP连接仅有两方进行通信,所以不能用于多播和广播。 全双工。 3、3次握手和4次挥手 MSS选项:最大分段大小,以字节数定义一个计算机或通信设备所能接受的分段的最大...

    1、提供面向连接的可靠的字节流服务(一个报文发送端可以一次或多次发,接收端可以一次或多次收,不必来一个读一个);UDP是面向数据报的无连接,客户端发一个,服务端就收一个,不会合并几个UDP数据报。

    2、一个TCP连接仅有两方进行通信,所以不能用于多播和广播。

    全双工。

    3、3次握手和4次挥手

    MSS选项:最大分段大小,以字节数定义一个计算机或通信设备所能接受的分段的最大数据量。它并不会计算 TCP 或 IP 协议头的大小。默认的 TCP 最大分段大小是 536。[2]当一个主机想要把 MSS 设置到一个非默认的值时,MSS 大小会以一个 TCP 可选项的方式在握手时的 SYN 包中定义。由于最大分段大小被一个 TCP 参数控制,主机可以在接下来的任意分段中改变它。每个数据流的方向都可以使用不同的 MSS。

    只出现在SYN报文中。MSS = MTU - 20 - 20           避免分段

    4、TCP状态变迁

     

    TCP同时打开只建立一条连接,也支持同时关闭

    RST异常终止或中途终止

    捎带ack时延200ms

    Nagle算法:一个TCP连接上最多只能有一个未被确认的未完成的小分组。(广域网上采用,局域网内很少采用)

    慢启动:观察新分组进入网络的速率应该与另一端返回确认的速率相同而进行工作,不必一次发完滑动窗口内的数据;发送方取拥塞控制与通告窗口中的最小值作为发送上限。拥塞窗口是发送方使用的流量控制,通告窗口是接收方使用的流量控制。

    5、超时与重传

    对每个TCP连接,有4个不同的定时器:重传定时器、坚持定时器、保活定时器和2MSL定时器

    RTT估时器

    6、Telnet比Relogin复杂

    FTP:两条TCP链路,控制连接与数据连接

     

    展开全文
  • C#TCP通信例子

    千次下载 热门讨论 2012-07-10 22:53:52
    一个C#写的TCP通信例子,解压有TCPServer和TCPClient两部分的源码,用vs2010编写
  • python TCP通信详解

    万次阅读 多人点赞 2019-08-24 21:09:28
    TCP简介 TCP介绍 ...TCP通信需要经过创建连接、数据传送、终止连接三个步骤。 TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,“打电话”" TCP特点 1. 面向...

    TCP简介

    TCP介绍

    TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

    TCP通信需要经过创建连接、数据传送、终止连接三个步骤。

    TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,“打电话”"

    TCP特点

    1. 面向连接

    通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。

    双方间的数据传输都可以通过这一个连接进行。

    完成数据交换后,双方必须断开此连接,以释放系统资源。

    这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。

    2. 可靠传输

    1)TCP采用发送应答机制

    TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功

    2)超时重传

    发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。

    TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传

    3)错误校验

    TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。

    4) 流量控制和阻塞管理

    流量控制用来避免主机发送得过快而使接收方来不及完全收下。

    TCP与UDP的不同点

     TCPUDP
    1TCP的传输是可靠传输。UDP的传输是不可靠传输。
    2TCP是基于连接的协议,在正式收发数据前,必须和对方建立可靠的连接。UDP是和TCP相对应的协议,它是面向非连接的协议,它不与对方建立连接,而是直接把数据包发送出去
    3TCP是一种可靠的通信服务,负载相对而言比较大,TCP采用套接字(socket)或者端口(port)来建立通信。UDP是一种不可靠的网络服务,负载比较小。
    4TCP和UDP结构不同,TCP包括序号、确认信号、数据偏移、控制标志(通常说的URG、ACK、PSH、RST、SYN、FIN)、窗口、校验和、紧急指针、选项等信息。UDP包含长度和校验和信息。
    5TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。
    6TCP在发送数据包前在通信双方有一个三次握手机制,确保双方准备好,在传输数据包期间,TCP会根据链路中数据流量的大小来调节传送的速率,传输时如果发现有丢包,会有严格的重传机制,故而传输速度很慢。UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
    7TCP支持全双工和并发的TCP连接,提供确认、重传与拥塞控制。UDP适用于哪些系统对性能的要求高于数据完整性的要求,需要“简短快捷”的数据交换、需要多播和广播的应用环境。

    tcp通信模型

    udp通信模型中,在通信开始之前,不需要建立相关的链接,只需要发送数据即可,类似于生活中,“写信"
    tcp通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,“打电话”"

    在这里插入图片描述
    在这里插入图片描述

    TCP网络程序

    tcp客户端和服务端

    所谓的服务器端:就是提供服务的一方,而客户端,就是需要被服务的一方

    tcp客户端构建流程

    tcp的客户端要比服务器端简单很多,如果说服务器端是需要自己买手机、查手机卡、设置铃声、等待别人打电话流程的话,那么客户端就只需要找一个电话亭,拿起电话拨打即可,流程要少很多

    客户端一般不绑定端口

    from socket import *
    
    # 创建socket
    tcp_client_socket = socket(AF_INET, SOCK_STREAM)
    
    # 目的信息
    server_ip = input("请输入服务器ip:")
    server_port = int(input("请输入服务器port:"))
    
    # 链接服务器
    tcp_client_socket.connect((server_ip, server_port))
    
    # 提示用户输入数据
    send_data = input("请输入要发送的数据:")
    
    tcp_client_socket.send(send_data.encode("gbk"))
    
    # 接收对方发送过来的数据,最大接收1024个字节
    recvData = tcp_client_socket.recv(1024)
    print('接收到的数据为:', recvData.decode('gbk'))
    
    # 关闭套接字
    tcp_client_socket.close()
    
    请输入服务器ip:10.10.0.47
    请输入服务器port:8080
    请输入要发送的数据:你好啊
    接收到的数据为: 我很好,你呢
    

    网络调试助手:https://www.cr173.com/soft/746079.html在这里插入图片描述

    TCP服务器

    tcp服务器的构建流程

    如果想要完成一个tcp服务器的功能(联通买座机接听电话为例子),需要的流程如下:

    1. socket创建一个监听套接字 (联通买座机)
    2. bind绑定ip和port (插电话卡)
    3. listen使套接字变为可以被动链接 (接电话服务要开通)套接字默认是连接别人,需要化主动为被动
    4. accept等待客户端的链接 (等待别人给你打电话)
      返回新的通信套接字,和地址 (主机把这个连接转移给一个客服,然后给出来电显示)
    5. recv/send接收发送数据 (接通电话,进行交流)
    from socket import *
    
    # 创建socket
    tcp_server_socket = socket(AF_INET, SOCK_STREAM)
    
    # 本地信息
    address = ('', 7788)
    
    # 绑定
    tcp_server_socket.bind(address)
    
    # 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
    listen里的数字表征同一时刻能连接客户端的程度.
    tcp_server_socket.listen(128)
    
    # 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务
    # client_socket用来为这个客户端服务
    # tcp_server_socket就可以省下来专门等待其他新客户端的链接
    # clientAddr 是元组(ip,端口)
    client_socket, clientAddr = tcp_server_socket.accept()
    
    # 接收对方发送过来的数据,和udp不同返回的只有数据
    recv_data = client_socket.recv(1024)  # 接收1024个字节
    print('接收到的数据为:', recv_data.decode('gbk'))
    
    # 发送一些数据到客户端
    client_socket.send("thank you !".encode('gbk')) #
    
    # 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
    client_socket.close()
    

    tcp注意点

    • tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
    • tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
    • tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
    • 当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
    • 当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
    • listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
    • 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信,因为accept返回了新的套接字。
    • 关闭accept返回的套接字意味着这个客户端已经服务完毕
    • 当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,就是recv()返回为空, sendto不能发送空消息,因此服务器可以通过返回数据的长度来区别客户端是否已经下线

    文件下载器

    服务器

    from socket import *
    import sys
    
    
    def get_file_content(file_name):
        """获取文件的内容"""
        try:
            with open(file_name, "rb") as f:
                content = f.read()
            return content
        except:
            print("没有下载的文件:%s" % file_name)
    
    
    def main():
    
        if len(sys.argv) != 2:
            print("请按照如下方式运行:python3 xxx.py 7890")
            return
        else:
            # 运行方式为python3 xxx.py 7890
            port = int(sys.argv[1])
    
    
        # 创建socket
        tcp_server_socket = socket(AF_INET, SOCK_STREAM)
        # 本地信息
        address = ('', port)
        # 绑定本地信息
        tcp_server_socket.bind(address)
        # 将主动套接字变为被动套接字
        tcp_server_socket.listen(128)
    
        while True:
            # 等待客户端的链接,即为这个客户端发送文件
            client_socket, clientAddr = tcp_server_socket.accept()
            # 接收对方发送过来的数据
            recv_data = client_socket.recv(1024)  # 接收1024个字节
            file_name = recv_data.decode("utf-8")
            print("对方请求下载的文件名为:%s" % file_name)
            file_content = get_file_content(file_name)
            # 发送文件的数据给客户端
            # 因为获取打开文件时是以rb方式打开,所以file_content中的数据已经是二进制的格式,因此不需要encode编码
            if file_content:
                client_socket.send(file_content)
            # 关闭这个套接字
            client_socket.close()
    
        # 关闭监听套接字
        tcp_server_socket.close()
    
    
    if __name__ == "__main__":
        main()
    

    客户端

    from socket import *
    
    
    def main():
    
        # 创建socket
        tcp_client_socket = socket(AF_INET, SOCK_STREAM)
    
        # 目的信息
        server_ip = input("请输入服务器ip:")
        server_port = int(input("请输入服务器port:"))
    
        # 链接服务器
        tcp_client_socket.connect((server_ip, server_port))
    
        # 输入需要下载的文件名
        file_name = input("请输入要下载的文件名:")
    
        # 发送文件下载请求
        tcp_client_socket.send(file_name.encode("utf-8"))
    
        # 接收对方发送过来的数据,最大接收1024个字节(1K)
        recv_data = tcp_client_socket.recv(1024)
        # print('接收到的数据为:', recv_data.decode('utf-8'))
        # 如果接收到数据再创建文件,否则不创建
        if recv_data:
            with open("[接收]"+file_name, "wb") as f:
                f.write(recv_data)
    
        # 关闭套接字
        tcp_client_socket.close()
    
    
    if __name__ == "__main__":
        main()
    
    展开全文
  • Netty实现TCP通信

    千次阅读 2020-08-04 17:24:03
    Netty实现TCP通信 Netty实现网络通信时实际上是根据不同的通道类型来实现不同类型的协议处理 1. 服务端实现 public class NettyDiscardServer { public static void main(String[] args) throws ...
  • tcp通信过程

    千次阅读 2019-08-09 16:05:05
    TCP通信过程包括三个步骤:建立TCP连接通道,传输数据,断开TCP连接通道。如图1所示,给出了TCP通信过程的示意图。 上图主要包括三部分:建立连接、传输数据、断开连接。 建立TCP连接很简单,通过三次握手便可...
  • 浅析TCP通信原理

    万次阅读 2017-09-10 20:08:37
    TCP通信 TCP是面向连接的通信,所以在通信之前,客户端与服务器端必须通过三次握手建立连接,然后在通信完毕,还要通过四次挥手断开连接。 (一)相关函数 1.创建套接字 domain:地址类型,ipv4、ipv6、...
  • C语言实现TCP通信

    千次阅读 2019-12-26 10:36:19
    C语言通过socket编程实现TCP通信 服务端客户端通信例子:socket tcp 通信1,socket tcp通信2,udp使用讲解,socket udp通信例子 TCP/IP协议 叫做传输控制/网际协议,又叫网络通信协议。实际上,它包含上百个功能的...
  • Python实现TCP通信

    万次阅读 2019-09-03 23:19:48
    使用socket实现tcp通信,需导入socket模块 1、服务端 主要步骤: (1)创建socket:socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) family:AF_INET , AF_INET6, AF_UNIX, AF_CAN, AF_...
  • Java中网络编程、TCP通信与UDP通信

    千次阅读 2019-07-24 09:00:50
    目录 一、网络通讯协议 1、概述 2、IP 地址和端口号 ...三、TCP 通信 1、ServerSocket 类(实现服务端) 2、Socket 类(实现客户端) 3、TCP 通信实例 四、UDP 通信 1、DatagramPacket...
  • Modbus TCP通信

    千次阅读 2018-06-06 14:51:57
    Modbus TCP通信概述MODBUS/TCP是简单的、中立厂商的用于管理和控制自动化设备的MODBUS系列通讯协议的派生产品,显而易见,它覆盖了使用TCP/IP协议的“Intranet”和“Internet”环境中MODBUS报文的用途。协议的最通用...
  • C++中的TCP通信

    千次阅读 2018-07-17 10:24:03
    在TCP/IP协议下,最常见的就是TCP和UDP,不过C++中的UDP我还没有看过,今天就简单说说C++中的TCP通信,大致分成下面四部分: TCP简介 TCP通信流程 Windows下TCP通信API的简介 TCP通信的C++代码 1,TCP简介 ...
  • Lua语言使用TCP通信

    千次阅读 2020-07-31 17:06:34
    TCP通信server.lua --lua的TCP通信发送字符串末尾必须添加\n --server socket = require("socket") --调用socket包 ip = "192.168.3.184" --程序设置自己为Server端,设置自己的ip地址 port = 8080 --设置端口 se
  • TCP通信丢包原因总结

    千次阅读 2020-04-04 16:40:17
    TCP通信丢包原因总结 TCP在不可靠的网络上实现可靠的传输,必然会有丢包。TCP是一个“流”协议,一个详细的包将会被TCP拆分为好几个包上传,也是将会把小的封裝成大的上传,这就是说TCP粘包和拆包难题。 ...
  • Labview 的TCP通信

    千次阅读 2020-05-30 21:59:57
    Labview 的TCP通信 一、实验目的 利用Labview编写VI程序,与网络调试助手之间实现信息传输。 二、实验材料 网络调试助手程序,Labview的TCP程序框图和前面板 三、实验过程 1.使用Labview编写好相应VI程序框图,如下...
  • 在Linux上搭建TCP通信测试服务器

    千次阅读 2018-11-21 15:44:02
    在Linux上搭建TCP通信测试服务器 前言 在 Linux平台上搭建TCP通信测试服务器的方法多种多样,本文就列举出来非常简单的服务器搭建方法。 搭建TCP通信测试服务器的主要作用就是为了验证TCP通信连接和通信链路是否正常...
  • Java网络通信Part2:TCP通信及Socket

    千次阅读 2020-03-02 21:14:02
    一、TCP通信概念 TCP通信:实现两台计算机之间的数据交互 严格区分客户端(Client)和服务器端(Server) 客户端和服务端会建立一个逻辑连接 这个连接中包含一个对象 即IO对象 客户端和服务端即可使用IO对象来进行通信 ...
  • 局域网下两台电脑如何进行TCP通信 现在需要软件与硬件进行通信 主要通过TCP/UDP进行通信
  • ESP8266的TCP通信

    千次阅读 2017-06-16 13:39:36
    上一篇文章讲述了如何进行UDP通信;好了,废话不多少;直接进入主题; 上一篇的UDP的时候,...当你连连接上wifi 的时候,你需要设置一下你的TCP通信(这一点和UDP是一样的);我们在my_station_init()函数中设置一下; 这
  • Qt TCP通信,多线程服务器端

    万次阅读 多人点赞 2016-05-15 12:49:56
    相信许多初学Qt的同学都会和我一样遇到这样的问题:一、Qt TCP通信在使用nextPendingConnect后,服务器端就只会与最后接入的客户端通信,这个时候就会考虑继承QThread实现多线程,从而实现多个客户端与服务器端通信...
  • http通信和tcp通信

    千次阅读 2013-10-18 16:42:06
     tcp通信,建立了连接(程序上是调用WINSOCKAPI,即通过申请套接字来建立,操作系统内部实际是通过三次握手来实现的),即可直接进行通信了,这里的“直接”,是指客户端可以直接收消息,即无需客户端发出请求,...
  • python modbus 实现TCP 通信

    万次阅读 多人点赞 2019-07-17 11:38:57
    python modbus_tk 实现tcp 通信下载对应pip由于没有硬件设备,采用软件模拟,软件下载地址为下载安装好开始连接,第一次连接需要激活模拟创建一个HOLDING_REGISTERS点击左上角file-new依次创建 以下 模拟器点击...
  • 基于QT的TCP通信

    千次阅读 2019-06-20 16:28:25
    一、linux下的tcp通信过程 其中bind绑定,会固定一个端口,否则是随机的。 一个链接是由双方的ip和端口组成的,固定端口保证源的不变性, 这样另一端在任何时候访问的目的都是一致的,也可以说这个端口提供了什么...
  • TCP通信socket缓存读取阻塞

    千次阅读 2017-07-12 13:30:08
    tcp通信——socket缓存读取阻塞 TCP通信过程,主要是数据的收发,最近一直在学习这方面的知识,其中有很多的细节部分确实是没有接触到,即便是一个小小的知识点,也会导致编程半天没有进展,需要查找很多的资料来...
  • 《MFC网络通信》Part 2 简单TCP通信

    千次阅读 热门讨论 2016-03-20 13:02:52
    《MFC网络通信》Part 2 简单TCP通信 一般TCP通信软件都分为服务器端和客户端。 TCP服务器端由一个侦听So
  • Go语言实现TCP通信

    千次阅读 2018-10-19 15:13:00
    章节 go 优势 go 实现 TCP 通信 1 go 语言优势 ...2 go 实现TCP通信 2.1 server.go unix 网络编程步骤: Server-&gt;Bind-&gt;Listen-&gt;Accept go 语言实现 socket 编程步骤: Listen...
  • 通过python实现tcp通信

    千次阅读 2018-12-06 21:10:31
    如何通过Python实现PC间TCP通信一、Client端二、Server端 一、Client端 # -*- encoding: utf-8 -*- import socket import sys IP = '192.168.43.38' # 填写服务器端的IP地址 port = 40005 # 端口号必须一致 s...
  • S7-1200PLC Modbus TCP通信

    千次阅读 2020-03-24 22:31:41
    硬件:cpu 1214C 目的:建立两台cpu之间的Modbus TCP通信 软件:Portal V14SP1
  • Python两台电脑实现TCP通信

    万次阅读 2018-01-11 10:20:55
    为了实现Nao机器人与电脑端的TCP通信,于是研究了一下Python实现TCP通信,在网上也看到了很多例子,但大多都是在一台机器上验证。在两台机器上使用,出了一些小故障。 注意:若两台电脑通信出了问题,若能ping通!...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 470,322
精华内容 188,128
关键字:

tcp通信