【网络编程】demo版TCP网络服务器实现

一、引入

UDP和TCP的区别:

对于TCP协议有几个特点:

1️⃣ 传输层协议
2️⃣ 有连接(正式通信前要先建立连接)
3️⃣ 可靠传输(在内部帮我们做可靠传输工作)
4️⃣ 面向字节流

对于UDP协议有几个特点:

1️⃣ 传输层协议
2️⃣ 无连接
3️⃣ 不可靠传输
4️⃣ 面向数据报

可以看到TCP对比UDP会建立链接

其他的接口跟UDP其实没什么区别:【网络编程】demo版UDP网络服务器实现

二、服务端实现

2.1 创建套接字socket

在通信之前要先把网卡文件打开。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

RETURN VALUE
On success, a file descriptor for the new socket is returned.  
On error, -1 is returned, and errno is set appropriately.

这个函数的作用是打开一个文件,把文件和网卡关联起来。

参数介绍:

domain:一个域,标识了这个套接字的通信类型(网络或者本地)。
在这里插入图片描述
只用关注上面两个类,第一个AF_UNIX表示本地通信,而AF_INET表示网络通信。
type:套接字提供服务的类型。
在这里插入图片描述
这一章我们讲的式TCP,所以使用SOCK_STREAM
protocol:想使用的协议,默认为0即可,因为前面的两个参数决定了,就已经决定了是TCP还是UDP协议了。

返回值:

成功则返回打开的文件描述符(指向网卡文件),失败返回-1。

而从这里我们就联想到系统中的文件操作,未来各种操作都要通过这个文件描述符,所以在服务端类中还需要一个成员变量表示文件描述符。

#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include "log.hpp"

class TCPServer
{
   
static const uint16_t gport = 8080;
public:
    TCPServer(cosnt uint16_t& port = gport)
        : _sock(-1)
        , _port(port)
    {
   }

    void InitServer()
    {
   
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if(_sockfd == -1)
        {
   
            std::cerr << "create socket error" << std::endl;
            exit(1);
        }
        std::cout << "create socket success" << std::endl;
    }

    void start()
    {
   }
private:
    int _sock;
    uint16_t _port;
};

2.2 绑定bind

#include <sys/socket.h>

int bind(int socket, const struct sockaddr *address,
       socklen_t address_len);

RETURN VALUE
Upon successful completion, bind() shall return 0; 
otherwise, -1 shall be returned and errno set to indicate the error.

参数介绍:

socket:创建套接字的返回值。
address:通用结构体(【网络编程】socket套接字有详细介绍)。
address_len:传入结构体的长度。

所以我们要先定义一个sockaddr_in结构体填充数据,在传递进去。
在这里插入图片描述
然后就是跟UDP一样,先初始化结构体,再处理IP和端口。
要注意IP要绑定任意IP也就是INADDR_ANY
至于为什么再上一章【网络编程】demo版UDP网络服务器实现有过详细讲解。

void InitServer()
{
   
    _sock = socket(AF_INET, SOCK_STREAM, 0);
    if(_sockfd == -1)
    {
   
        std::cerr << "create socket error" << std::endl;
        exit(1);
    }
    std::cout << "create socket success" << std::endl;
    struct sockaddr_in si;
    // 初始化结构体
    bzero(&si, sizeof si);
    si.sin_family = AF_INET;
    si.sin_port = htons(_port);// 主机转网络序列
    si.sin_addr.s_addr = INADDR_ANY;
    if(bind(_sock, (struct sockaddr*)&si, sizeof si) < 0)
    {
   
        std::cout << "bind socket error" << std::endl;
        exit(1);
    }
    std::cout << "bind socket success" << std::endl;
}

2.3 设置监听状态listen

TCP跟UDP的不同在这里就体现了出来。
要把socket套接字的状态设置为listen状态。只有这样才能一直获取新链接,接收新的链接请求。

举个例子:
我们买东西如果出现了问题会去找客服,如果客服不在那么就回复不了,所以规定了客服在工作的时候必须要时刻接收回复消息,这个客服所处的状态就叫做监听状态

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int listen(int sockfd, int backlog);

RETURN VALUE
On success, zero is returned.  
On error, -1 is returned, and errno is set appropriately.

关于第二个参数backlog后边讲TCP协议的时候介绍,目前先直接用。

static const int gbacklog = 10;
void InitServer()
{
   
    _sock = socket(AF_INET, SOCK_STREAM, 0);
    if(_sock == -1)
    {
   
        std::cerr << "create socket error" << std::endl;
        exit(1);
    }
    std::cout << "create socket success" << std::endl;
    struct sockaddr_in si;
    // 初始化结构体
    bzero(&si, sizeof si);
    si.sin_family = AF_INET;
    si.sin_port = htons(_port);// 主机转网络序列
    si.sin_addr.s_addr = INADDR_ANY;
    if(bind(_sock, (struct sockaddr*)&si, sizeof si) < 0)
    {
   
        std::cout << "bind socket error" << std::endl;
        exit(1);
    }
    std::cout << "bind socket success" << std::endl;
    // 设置监听状态
    if(listen(_sock, gbacklog
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

命由己造~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值