TCP/IP 学习笔记(1)- Hello World

本篇文章简单介绍了TCP/IP 通信,服务端使用的是 Linux ,我使用的Linux为 Deepin 国产Linux系统。客户端使用的是 Windows 系统,界面使用 Qt 完成的,基本的Socket编程使用的是操作系统提供的API。本系列文章所有例程均参考 尹圣雨 著《TCP/IP网络编程》 一书,客户端界面如下图所示:

TCP Client
我的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;
}

服务端的流程如下:

  1. 使用函数 socket() 创建Socket ,socket 是计算机网络通信的工具。它是通过操作系统进行管理的。
  2. 使用函数 bind() ,为创建的 Socket 分配IP地址和端口号。
  3. 使用函数 listen() ,将 Socket 设置为可就受连接的状态。
  4. 使用函数 accept(),接受数据连接请求。
  5. 使用函数 recvsend, 发送和接收数据。

关于每个函数的具体使用,在后续的文章中介绍,下面是客户端部分的完整代码:

头文件

#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通信如下步骤:

  1. 使用函数 socket() 创建socket.
  2. 使用函数 connect() 绑定IP地址和自动分配端口号,并连接主机。
发布了88 篇原创文章 · 获赞 79 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/douzhq/article/details/91128296