博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
socket 编程入门教程(三)TCP原理:2、设计TCP socket的类(上)
阅读量:6262 次
发布时间:2019-06-22

本文共 2453 字,大约阅读时间需要 8 分钟。

hot3.png

    我们在第1节中讲过,socket是一个int的文件描述符(WinSock中直接是一种抽象的描述符),我们通过对这个描述符发出指令操作socket。这是C语言的思想,在面向对象的思想中,最好socket本身是一种对象,各种方法由对象本身发出。用面向对象的思想封装socket并不困难,而且,对于描述socket的概念可能更加直观,这一节,我们边介绍socket和TCP的概念边对socket进行OO封装。

首先,每一个socket对象都具有唯一的socket文件描述符,这样可以很好的对应socket的概念。所以我们构建一个基类,并让其成为纯虚函数——这是因为socket文件描述符必须在具体的构造中才能出现,然后仍然保留一个返回原始的socket文件描述符的接口,这是为了不方便归结到类函数中的函数所预留准备的,比如极其重要的select()我们会在后面讲到,所谓有备无患。

class BaseSock{

protected:
    
int sockFD;
public:
    BaseSock();
    
virtual ~BaseSock() = 0;
    
const int& showSockFD() const;
};

函数实现:

//class BaseSock

BaseSock::BaseSock():
sockFD(
-1)
{}
BaseSock::
~BaseSock()
{}
const int& BaseSock::showSockFD() const
{
    
return sockFD;
}

我们把sockFD的初始值设置为-1,表明在没有派生类构造的时候这是一个非法的文件描述符号(File Descriptor)。

接下来,我们简单回顾一下第一节对于TCP Server的建立:
首先,我们需要建立一个监听socket,然后激活其监听;
然后,在client端连接信息过来之后,通过监听端口将客户端的信息传递给新的socket,从而建立通讯socket。
我们先构建listen socket:

class TCPListenSock: public BaseSock{

private:
    sockaddr_in listenSockAddr;
public:
    
explicit TCPListenSock(unsigned short listen_port);
    
~TCPListenSock();
    
void TCPListen(
        
int max_connection_requests = 10const;
};

TCPListenSock建立的目的的就是被动的等待client端寻找握手的connect(),从而收集client端的sock地址信息(包含了IP地址和端口号),然后在需要的时候传递给新的socket建立通讯socket。

TCPListenSock::TCPListenSock(unsigned short listen_port)

{
    sockFD = socket(PF_INET,
                    SOCK_STREAM,
                    IPPROTO_TCP);
    
if (sockFD < 0) {
        sockClass::error_info(
"socket() failed.");
    }
    memset(
&listenSockAddr, 0sizeof(listenSockAddr));
    listenSockAddr.sin_family 
= AF_INET;
    listenSockAddr.sin_addr.s_addr 
= htonl(INADDR_ANY);
    listenSockAddr.sin_port 
= htons(listen_port);
    
if (bind(    sockFD,
                (sockaddr
*)&listenSockAddr,
                
sizeof(listenSockAddr)) < 0) {
        sockClass::error_info(
"bind() failed.");
    }
}
TCPListenSock::
~TCPListenSock()
{
    close(sockFD);
}

TCPListenSock通过调用socket()建立sockFD;通过指定端口好指明监听端口,这是为客户端能够找到这个端口所必须的。而IP地址设置为INADDR_ANY,其实就是0,这意味着可以是任何一个server端所拥有的IP。TCPListenSock通过bind()将sockFD和SockAddr绑定在一起。这个sockFD只有本机的SockAddr意味着:1、无法建立连接,只有接受数据报;2、只能接受信息,因为没有远程目的地的SockAddr而无法发出信息。

而这对于TPC建立连接的过程来说,既是足够的,也是必须的。事实上,client端发出的第一个握手数据报就被这个sockFD所接收,而返回给client的握手应答和对client的握手请求则由新的sockFD发出。
listen()是将TCPListenSock激活为监听状态,如果不激活,那么任何握手的连接请求都将被这个sockFD所忽略。

void TCPListenSock::TCPListen(

                        int max_connection_requests) const
{
    
if (listen(    sockFD,
                max_connection_requests) 
< 0) {
        sockClass::error_info(
"listen() failed.");
    }
}

这个函数看来似乎有些多此一举,因为这个监听是可以整合到构造函数中的,也就是说,我们可以一旦建立TCPListenSock就令其激活,事实上这正是SDL_net中的做法,也是让我感到不严谨的地方,因为监听本身是socket的一个概念。

转载于:https://my.oschina.net/GeorgeSu/blog/264193

你可能感兴趣的文章
旷视科技 CSG 算法负责人姚聪:深度学习时代的文字检测与识别技术 | AI 研习社 103 期大讲堂...
查看>>
构建docker镜像
查看>>
《未来简史》读后感
查看>>
Flink靠什么征服饿了么工程师?
查看>>
VB VBA VBS有什么区别?
查看>>
CSS3 box-shadow
查看>>
手机 APP 无法连接服务器,DNS被篡改被劫持?
查看>>
Jboot 2.0.1 发布,新增基于 Fescar 的分布式事务支持
查看>>
使用RNA-seq数据通过网络熵评估肿瘤内异质性
查看>>
Scrapy基础——Spider
查看>>
Airbnb 宣布放弃使用 React Native,回归使用原生技术
查看>>
PyCharm for Mac快捷键小记
查看>>
Html5的从0到1-Html5的web Storage概述(16)
查看>>
中国IT行业盛行,程序员“过多”是主要原因?
查看>>
史上最难的一道Java面试题:分析篇
查看>>
HDFS常用命令(方便大家记忆版)
查看>>
kafka原理与实践(原创)
查看>>
如何在excel单元格中插入图片批注
查看>>
Android 基础动画之补间动画详解
查看>>
业界 | 全球最大生物识别数据库被判定合法
查看>>