封装时 send 函数为啥使用 const string & buf 作为参数类型

bool send(const string &buffer)   // buffer不要用const char *

const string & buf 既可以接收 string 也可以接受 char *. 估计是对 char * 进行了隐式转换成了 string.

send 函数的参数为啥是 buf.data() 和 buf.size(), 而不是 buf.c_str() 和 buf.length

if ((::send(m_clientfd,buffer.data(),buffer.size(),0))<=0) return false;
  • buf.data()buf.c_str() 都指向的是内容的指针,但是语义不一样。 data 表示的就是原始数据,而 c_str 表示的是转化为 char *.
  • buf.size() 的语义是原始内容的大小,而 length 表示的是字符串的长度。

所以都是因为语义不合适。虽然都能用,但是确实不合适。

recv 函数的参数为啥是 & buf[0] 而不是 buf.c_str() 或者 buf.data()

int readn=::recv(m_clientfd,&buffer[0],buffer.size(),0);  // 直接操作buffer的内存。

因为后面两种返回的都是带有 const, 只有 &buf[0] 才没有 const, 适合对内容进行修改。

recv 函数对字符串手动操作的注意点:

// 接收服务端的报文,成功返回true,失败返回false。
// buffer-存放接收到的报文的内容,maxlen-本次接收报文的最大长度。
bool recv(string &buffer,const size_t maxlen)
{ // 如果直接操作string对象的内存,必须保证:1)不能越界;2)操作后手动设置数据的大小。
  buffer.clear();         // 清空容器。
  buffer.resize(maxlen);  // 设置容器的大小为maxlen。
  int readn=::recv(m_clientfd,&buffer[0],buffer.size(),0);  // 直接操作buffer的内存。
  if (readn<=0) { buffer.clear(); return false; }
  buffer.resize(readn);   // 重置buffer的实际大小。

  return true;
}
  • 写入之前,=resize= 的空间一定要够,不能越界。
  • 写入之后,根据写入的数据量,重新通过 resize 来把空间调整为接收到的数据量,方便后续的 string 操作。

参考

封装 socket 客户端