本篇文章简单介绍了TCP/IP 通信,服务端使用的是 Linux ,我使用的Linux为 Deepin 国产Linux系统。客户端使用的是 Windows 系统, 界面使用 Qt 完成的,基本的Socket编程使用的是操作系统提供的API。本系列文章所有例程均参考 尹圣雨 著《TCP/IP网络编程》 一书,客户端界面如下图所示:
我的Linux服务器的IP地址为 192.168.150.130 , Server的端口号为 9003
下面是TCP Server的完整代码:
#include <iostream> #include <QDebug> #include <sys/socket.h> #include <unistd.h> #include <arpa/inet.h> #include <QString> int main(int argc, char *argv[]) { char* portString = "9003"; int socketHnd = socket(PF_INET, SOCK_STREAM, 0); if (socketHnd == -1) qDebug() << "Create TCP Socket Error!"; //std::cout << "Create Socket Successed!"; qDebug() << "Create Socket Successed!"; // bind sockaddr_in sockInfo; memset(&sockInfo, 0, sizeof(sockInfo)); sockInfo.sin_family = AF_INET; sockInfo.sin_addr.s_addr = htonl(INADDR_ANY); sockInfo.sin_port = htons(atoi(portString)); if (bind(socketHnd, (sockaddr*)&sockInfo, sizeof(sockInfo)) == -1) qDebug() << "bind Error!"; // listen if (listen(socketHnd, 5) == -1) qDebug() << "listion Error!"; while(1) { // accept socklen_t clentAddrInfoSize = sizeof(sockInfo); int clentSocketHnd = accept(socketHnd, (sockaddr*)&sockInfo, &clentAddrInfoSize); if (clentSocketHnd == -1) qDebug() << "accept error!"; char pData[50] = {0}; // Recv Data while (recv(clentSocketHnd, pData, sizeof(pData), 0) > 0) { // Send Data send(clentSocketHnd, pData, sizeof(pData), 0); } close(clentSocketHnd); } close(socketHnd); return 0; }
服务端的流程如下:
关于每个函数的具体使用,在后续的文章中介绍,下面是客户端部分的完整代码:
头文件
#pragma once #include <QtWidgets/QWidget> #include <WinSock2.h> #include <QLineEdit> #include <QLabel> #include <QPushButton> #include <QTextEdit> #include <QSpinBox> class TcpClient : public QWidget { Q_OBJECT public: TcpClient(); ~TcpClient(); private slots: void onClickedConnectButton(void); void onClickedSendMessageButton(void); private: SOCKET m_Socket = INVALID_SOCKET; private: QTextEdit *m_TextEdit = nullptr; QLineEdit *m_IPLineEdit = nullptr; QSpinBox *m_PortEdit = nullptr; QPushButton *m_ConnectButton = nullptr; QLineEdit *m_SendMessageLineEdit = nullptr; };
源文件
#include "TCPClient.h" #include <QVBoxLayout> #include <QDebug> TcpClient::TcpClient() { QVBoxLayout *layout = new QVBoxLayout(this); // IP Address Layout QHBoxLayout *nTopLayout = new QHBoxLayout; QLabel *ipTag = new QLabel("Server IP Address:"); ipTag->setFixedWidth(150); ipTag->setAlignment(Qt::AlignVCenter | Qt::AlignRight); m_IPLineEdit = new QLineEdit; nTopLayout->addWidget(ipTag); nTopLayout->addWidget(m_IPLineEdit); // Port QHBoxLayout *nPortLayout = new QHBoxLayout; QLabel *portTag = new QLabel("Server Port:"); portTag->setFixedWidth(150); portTag->setAlignment(Qt::AlignVCenter | Qt::AlignRight); m_PortEdit = new QSpinBox; m_PortEdit->setMinimum(1000); m_PortEdit->setMaximum(10000); m_PortEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); nPortLayout->addWidget(portTag); nPortLayout->addWidget(m_PortEdit); // Connect m_ConnectButton = new QPushButton("Connect"); QObject::connect(m_ConnectButton, &QPushButton::clicked, this, &TcpClient::onClickedConnectButton); // Send Message QHBoxLayout *nSendMessageLayout = new QHBoxLayout; QLabel *sendMessageTag = new QLabel("Content:"); sendMessageTag->setFixedWidth(150); sendMessageTag->setAlignment(Qt::AlignVCenter | Qt::AlignRight); m_SendMessageLineEdit = new QLineEdit; QPushButton *button = new QPushButton("Send"); nSendMessageLayout->addWidget(sendMessageTag); nSendMessageLayout->addWidget(m_SendMessageLineEdit); nSendMessageLayout->addWidget(button); QObject::connect(button, &QPushButton::clicked, this, &TcpClient::onClickedSendMessageButton); // TextEdit m_TextEdit = new QTextEdit; m_TextEdit->setReadOnly(true); layout->addLayout(nTopLayout); layout->addLayout(nPortLayout); layout->addWidget(m_ConnectButton, 0, Qt::AlignRight | Qt::AlignVCenter); layout->addLayout(nSendMessageLayout); layout->addWidget(m_TextEdit); WSADATA data; if (WSAStartup(MAKEWORD(2, 2), &data) != 0) m_TextEdit->append("Startup Error!"); } TcpClient::~TcpClient() { if (INVALID_SOCKET != m_Socket) closesocket(m_Socket); WSACleanup(); } void TcpClient::onClickedConnectButton(void) { // 断开连接 if (m_Socket != INVALID_SOCKET) { closesocket(m_Socket); m_Socket = INVALID_SOCKET; m_TextEdit->append("Disconnect Server Success!"); m_ConnectButton->setText("Connect"); return; } // 创建Socket m_Socket = socket(PF_INET, SOCK_STREAM, 0); if (m_Socket == INVALID_SOCKET) { m_TextEdit->append("Create Socket Fail!"); return; } // 连接Server SOCKADDR_IN serverSockInfo; memset(&serverSockInfo, 0, sizeof(serverSockInfo)); serverSockInfo.sin_family = AF_INET; serverSockInfo.sin_addr.s_addr = inet_addr(m_IPLineEdit->text().toLocal8Bit().data()); serverSockInfo.sin_port = htons(m_PortEdit->value()); if (::connect(m_Socket, (SOCKADDR*)&serverSockInfo, sizeof(serverSockInfo)) == SOCKET_ERROR) { m_TextEdit->append("Connect Server Fail!"); // 关闭创建的Socket closesocket(m_Socket); m_Socket = INVALID_SOCKET; return; } m_ConnectButton->setText("DisConnect"); m_TextEdit->append("Connect Server Success!"); } void TcpClient::onClickedSendMessageButton(void) { if (m_Socket == INVALID_SOCKET) return; char* sendData = new char[30]; memset(sendData, 0, 30); strcpy(sendData, m_SendMessageLineEdit->text().toLocal8Bit().data()); // 发送数据 int sendLen = send(m_Socket, sendData, 30, 0); if (sendLen <= 0) return; QString sendMessa = "Send: %1"; sendMessa = sendMessa.arg(m_SendMessageLineEdit->text()); m_TextEdit->append(sendMessa); // 接收数据 char *pRecvData = new char[50]; memset(pRecvData, 0, 50); QString recvMessage = "Recv: "; if (recv(m_Socket, pRecvData, 50, 0) > 0) recvMessage += QString::fromLocal8Bit(pRecvData); m_TextEdit->append(recvMessage); delete[] pRecvData; }
客户端部分的代码相对简单
首先需要在项目中添加库文件 ws2_32.lib
在使用Socket相关的函数的时候,需要添加头文件 WinSock2.h
windows中的函数跟Linux中的函数基本类似,Windows中的函数就是根据Unix的函数设计的。
函数 WSAStartup() 和 WSACleanup() 为注册Windows网络的函数
客户点中进行Socket通信如下步骤:
预览: