socket 编程入门教程(一)TCP server 端:4、构造函数涉及的概念

话题回到“黑社会办公室”的例子,讲概念已经扯得比较远了,不过,这一节我们还得讲概念,不过好在有些程序的例子。如果大家不想翻回去看 TcpServer类的原型,我这里直接给出这个头文件的完整源代码:
// Filename: TcpServerClass.hpp

#ifndef TCPSERVERCLASS_HPP_INCLUDED
#define  TCPSERVERCLASS_HPP_INCLUDED

#include 
< unistd.h >
#include 
< iostream >
#include 
< sys / socket.h >
#include 
< arpa / inet.h >

class  TcpServer
{
private :
    
int  listenSock;
    
int  communicationSock;
    sockaddr_in servAddr;
    sockaddr_in clntAddr;
public :
    TcpServer(
int  listen_port);
    
bool  isAccept();
    
void  handleEcho();
};


#endif   //  TCPSERVERCLASS_HPP_INCLUDED
我们已经解释了为什么listenSock和communicationSock的类型是int,以及sockaddr_in是什么结构,现在来写这个类 的构造函数:
TcpServer::TcpServer( int  listen_port)
{
    
if  ( (listenSock  =  socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))  <   0  ) {
        
throw   " socket() failed " ;
    }

    memset(
& servAddr,  0 sizeof (servAddr));
    servAddr.sin_family 
=  AF_INET;
    servAddr.sin_addr.s_addr 
=  htonl(INADDR_ANY);
    servAddr.sin_port 
=  htons(listen_port);

    
if  ( bind(listenSock, (sockaddr * ) & servAddr,  sizeof (servAddr))  <   0  ) {
        
throw   " bind() failed " ;
    }

    
if  ( listen(listenSock,  10 <   0  ) {
        
throw   " listen() failed " ;
    }
}
好,先看看程序培养一下感觉,我们还得说概念。

数据封装(Data Encapsutation)

        我们前面说到了网络分层:链路——网络——传输——应用。数据从应用程序里诞生,传送到互联网上每一层都会进行一次封装:
Data>>Application>>TCP/UDP>>IP>>OS(Driver, Kernel & Physical Address)
我们用socket重点描述的是协议,包括网络协议(IP)和传输协议 (TCP/UDP)。
sockaddr重点描述的是地址,包括IP地址和TCP/UDP端口。

socket()函数

    我们从TcpServer::TcpServer()函数可以看到,socket和sockaddr的产生是可以相互独立的。socket()的函数原型 是:
int  socket( int  protocolFamily,  int  type,  int  protocol);
在Linux中的实现为:
#include  < sys / socket.h >

/*  Create a new socket of type TYPE in domain DOMAIN, using
   protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
   Returns a file descriptor for the new socket, or -1 for errors.  
*/
extern   int  socket ( int  __domain,  int  __type,  int  __protocol) __THROW;
第一个参数是协议簇(Linux里面叫作域,意思一样的),还是那句话,我们这篇教程用到的就仅仅是一个PF_INET(protocol family : internet),很多时候你会发现人们也经常在这里赋值为AF_INET,事实上,当前,AF_INET就是PF_INET的一个#define,但 是,写成PF_INET从语义上会更加严谨。这也就是TCP/IP协议簇中的IP协议(Internet Protocol),网络层的协议。
后 面两个参数定义传输层的协议。
第二个参数是传输层协议类型,我们教程里用到的宏,只有两个:SOCK_STREAM(数据流格式)和 SOCK_DGRAM(数据报格式);(具体是什么我们以后讨论)
第三个参数是具体的传输层协议。当赋值为0的时候,系统会根据传输层协议类型自 动匹配和选择。事实上,当前,匹配SOCK_STREAM的就是TCP协议;而匹配SOCK_DGRAM就是UDP协议。所以,我们指定了第二个参数,第 三个就可以简单的设置为0。不过,为了严谨,我们最好还是把具体协议写出来,比如,我们的例子中的TCP协议的宏名称:IPPROTO_TCP。

数 据的“地址”

        从数据封装的模型,我们可以看到数据是怎么从应用程序传递到互联网的。我们说过,数据的传送是通过socket进行的。但是socket只描述了协议类 型。要让数据正确的传送到某个地方,必须添加那个地方的sockaddr地址;同样,要能接受网络上的数据,必须有自己的sockaddr地址。
        可见,在网络上传送的数据包,是socket和sockaddr共同“染指”的结果。他们共同封装和指定了一个数据包的网络协议(IP)和IP地址,传输 协议(TCP/UDP)和端口号。

网络字节和本机字节的相互转换

        sockaddr结构中的IP地址(sin_addr.s_addr)和端口号(sin_port)将被封装到网络上传送的数据包中,所以,它的结构形式 需要保证是网络字节形式。我们这里用到的函数是htons()和htonl(),这些缩写的意思是:
h: host,主机(本机)
n: network,网络
to: to转换
s: short,16位(2字节,常用于端口号)
l: long, 32位(4字节,常用于IP地址)
“反过来”的函数也是存在的ntohs()和ntohl()。

动作与持续行为

        本节最后的一个概念可以跟计算机无关。作为动词,有些可以描述动作,有些是描述一重持续的行为状态的(就如同一般动词和be动词一样)。扯到C++来说, 我们可以把持续行为封装到函数内部,只留出动作的接口。事实上,构造函数中的bind()和listen()就是这种描述持续状态的行为函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值