1.TCp(2)发送接收缓冲区
Tcp的发送模式基本等同UDP,但不同点在于UDP是包式存取,而TCP是流式存取,每个包不带地址。
发送:send(“Hello”)与send(“World’);可能同时被一起取走;而发送send(“HelloWorld”);//有可能只取走hello。
问题:对于TCp socket,如何判断Recv()已取回全部数据?(何时超时)
定义边界:a->b(请求);b->a(响应),a->b(请求),b->a(xiangying);
在设计交互协议时,需要自己定义消息的边界。
方法1:先定义长度,后发数据;
方法2:每段加结束符。
流式存取:有多少取多少(不管先后顺序)。
例1:流式存取
Client:
// 连接服务器
OS_SockAddr serv_addr("127.0.0.1", 9555);
if( client_sock.Connect( serv_addr ) < 0)
{
printf("无法连接服务器!\n");
return -1;
}
char buf[1024];
int n;
client_sock.Send("hello", 5);
client_sock.Send("world", 5);
Server:
int TcpConn::Routine()
{
// 为client提供服务
char buf[1024];
int n ;
//OS_Thread::Msleep(5000);
// 接收客户的请求
n = m_WorkSock.Recv(buf, 1023);
buf[n] = 0;
printf("客户请求: %s \n", buf);
// 应答客户
strcpy(buf,"yes,ok!");
n=strlen(buf);
m_WorkSock.Send(buf, n);
// 关闭socket
m_WorkSock.Close();
return 0;
}
接收结果:helloworld,有多少,去多少!
例2:定义边界(先发送长度,再发数据)
client:
unsigned char bytes[2];
itob_16be(10, bytes);//按大端
client_sock.Send(bytes, 2);//发送数据大小
client_sock.Send("helloworld", 10);//发送数据
Server:
// 为client提供服务
unsigned char buf[1024];
int n ;
//m_WorkSock.Recv(buf,2);//接收两个字节的数据,但可能娶不到
// 使用边界
TcpHelper::WaitBytes(m_WorkSock,buf,2);
unsigned short count=btoi_16be(buf);//接收多长数据
n=TcpHelper::WaitBytes(m_WorkSock,buf,count);
buf[n]=0;
printf("客户请求: %s \n", buf);
m_WorkSock.Send("yes,OK!",8);
// 关闭socket
m_WorkSock.Close();
return 0;
阻塞:send满阻塞,recv空阻塞(这是默认方式)
例3:设置缓冲区大小
//扩大缓存
if(1)
{
// 获取Sendbuf的大小
int bufsize = 0; // 8k
socklen_t len = 4;
int ret = getsockopt(client_sock.hSock,SOL_SOCKET,
SO_SNDBUF,
(char*)&bufsize,&len);
if(ret < 0)
{
// 设置失败
printf("failed to get option!\n");
}
}
if(1)
{
// 设置SendBuf的大小
int bufsize = 128*1024; // 128K
int ret = setsockopt(client_sock.hSock,SOL_SOCKET,
SO_SNDBUF,
(const char*)&bufsize,sizeof(int));
if(ret < 0)
{
// 设置失败
}
}
TCP设置缓冲区是有用的。
2.数据包的传输
发送:OS把数据通过网卡,上传至交换机;
接收:OS通过网卡获得数据包。
UDP丢包:无法通知丢包;
TCP传输:传输后,OS会发一个ACK包,否则重传;
TCP传输是可靠传输,会失败;UDP是不会失败(只发送,不管理)