基本的TCP/IP Socket用法(一)

1、前言

ACE的IPC包按照组关联在一起:

连接器(ACE_SOCKET_Connector):主动建立连接--将流连接到服务器端

接收器(ACE_SOCKET_Acceptor):被动建立连接

流(ACE_SOCKET_Stream):传输数据

地址(ACE_INET_Addr):定义对端点进行寻址的手段

2、一个简单的客户如下:

// BaseSocket_Practice.cpp : 定义控制台应用程序的入口点。
//
#define ACE_NTRACE 0
#include "ace/Containers.h"
#include "ace/INET_Addr.h"
#include "ace/SOCK_Stream.h"
#include "ace/SOCK_Connector.h"
#include "ace/Log_Msg.h"

#include "ace/streams.h"//消息流文件重定向
#include "ace/Log_Record.h"//ACE_Log_Record对象定义
#include "ace/SString.h"
int ACE_TMAIN(int argc, ACE_TCHAR* argv[])
{
ACE_OSTREAM_TYPE *output=new std::ofstream("client.test");
ACE_LOG_MSG->msg_ostream(output);
ACE_LOG_MSG->set_flags(ACE_Log_Msg::OSTREAM);//日志重定向到文件
ACE_LOG_MSG->clr_flags(ACE_Log_Msg::STDERR);//禁用标准设备输出

ACE_TRACE(ACE_TEXT("client main"));

//服务器地址对象:服务器监听端口5000,服务器计算机名称:"localhost"
//端口为主机字节顺序,地址家族未定(AF_UNSPEC)
ACE_INET_Addr srvr(5000,ACE_LOCALHOST);

//客户端连接器
ACE_SOCK_Connector connector;

//将被连接到服务器的流对象,若客户端与服务器端连接成功,
//它会进入已连接状态,我们可以用它来与服务器通信
ACE_SOCK_Stream peer;

//连接服务器端
//连接参数:TCP协议,阻塞模式进行连接
//本地端口由本地计算机自动选取一个空闲的端口,若为对等通信(peer to peer),可能要自行指定本地端口
if(-1==connector.connect(peer,srvr))
{
   //连接失败,函数返回
   ACE_ERROR_RETURN((LM_ERROR,ACE_TEXT("%p/n"),ACE_TEXT("connect")),1);
}

ACE_DEBUG((LM_DEBUG,ACE_TEXT("connect succed./n")));

ACE_DEBUG((LM_DEBUG,ACE_TEXT("send string.../n")));

//链接成功开始通信
//发送7个字节的数据
//send_n使用事务发送数据,避免“短写”问题
//未设置超时参数,阻塞通信模式发包
peer.send_n("uptime/n",7);

ACE_DEBUG((LM_DEBUG,ACE_TEXT("recive string.../n")));

int bc;
iovec buf;
//接收信息,recvv自动分配连续缓冲区,存放数据
//未设置超时参数,阻塞通信模式收包
bc=peer.recvv(&buf);

ACE_DEBUG((LM_DEBUG,ACE_TEXT("%s"),ACE_reinterpret_cast(char*,buf.iov_base)));

//sendv()函数则用于以原子方式发送非连续的缓存区
iovec send[3];
send[0].iov_base=ACE_const_cast(ACE_TCHAR*,"up");
send[0].iov_len=2;
send[1].iov_base=ACE_const_cast(ACE_TCHAR*,"time");
send[1].iov_len=4;
send[2].iov_base=ACE_const_cast(ACE_TCHAR* ,"/n");
send[2].iov_len=1;

//以原子方式发送所有数据
peer.sendv(send,3);

iovec receive[3];
receive[0].iov_base=new char[2];
receive[0].iov_len=2;
receive[1].iov_base=new char[4];
receive[1].iov_len=4;
receive[2].iov_base=new char[1];
receive[2].iov_len=1;

//以原子方式接收所有数据
bc=peer.recvv(receive,3);

//处理接收到的数据
for(int i=0;i<3&&bc>0;i++)
{
   size_t wc=receive[i].iov_len;
   if(ACE_static_cast(size_t,bc)<wc)
   {
    wc=ACE_static_cast(size_t,bc);
   }
   ACE_DEBUG((LM_DEBUG,ACE_TEXT("%s/n"),ACE_reinterpret_cast(char*,receive[i].iov_base)));
   //清除对象,否则将导致内存泄漏
   delete[](ACE_reinterpret_cast(char*,receive[i].iov_base));
}
//通信完毕,关闭流
peer.close();

ACE_DEBUG((LM_DEBUG,ACE_TEXT("Socket closed./n")));

ACE_LOG_MSG->clr_flags(ACE_Log_Msg::OSTREAM);//非常重要,否则最后一条日志将尝试在已经删除的output对象上写
delete output;//释放内存
return 0;
}

1、端口复用复习

因为在Socket的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分。这种多重绑定便称之为端口复用。

这需要在Connect中指定本地端口,以及给第五个参数设定一个非零值,Connect就会为该连接设置为“端口复用”。

注意:端口复用仅仅适用于不同进程之间进行使用,同一进程中不同线程之间不得应用端口复用进行通信。因为不同计算机之间通信的识别决定于三个要素:计算机IP地址、进程、端口。因此不同进程之间,虽然共享端口,与同意服务器进行通信,却不会至于在通信中遇到混乱。在网上曾经看到有位程序员在一个进程中开了两个线程,建立了两个本地Socket绑定到相同端口,和同一台服务器通信,当然会运行出错的。因为这种情况下,两个Socket之间,三个要素完全相同,通信肯定存在问题。

2、小结

(1)ACE将连接对象和通信对象分离,使得职责清晰,避免了常见Socket的常识错误:直接在连接对象上进行通信;

(2)send_n()和recv_n()解决通信的“短读”和“短写”问题;

(3)sendv()和recvv()可实现非连续缓冲区数据的发送和接收,同时recvv()也可以接收数据多少未知(但尺寸不是大得不至于无法放进合理的存储空间中)。

(4)可以简单地实现,支持阻塞连接和非阻塞连接;

(5)可以简单地实现,支持阻塞数据发送;

(6)简单设置,可实现端口复用。

3、复习C++:static_cast和reinterpret_cast的区别

1、C++中的static_cast执行非多态的转换,用于代替C中通常的转换操作。因此,被做为隐式类型转换使用。比如:
int i;
float f = 166.7f;
i = static_cast<int>(f);
此时结果,i的值为166。
2、C++中的reinterpret_cast主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。比如:
int i;
char *p = "This is a example.";
i = reinterpret_cast<int>(p);
此时结果,i与p的值是完全相同的。reinterpret_cast的作用是说将指针p的值以二进制(位模式)的方式被解释为整型,并赋给i,一个明显的现象是在转换前后没有数位损失。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值