首页 > 代码库 > C++网络Socket
C++网络Socket
【多机测试】
若没有多台电脑,可以使用虚拟机
有多台电脑,连接交换机
观察IP
ipconfig(Linux下是ifconfig)
检测连通性
ping
【发送接收缓冲区】
SendTo()
a)存入数据和发送数据存在时间差
b)如果存入数据太快,太多,则发送缓冲区会满
RecvFrom()
a)不论是否取,OS总是把数据收下存好
b)RecvFrom是从RecvBuf里取走现成的数据,如果不及时取,则缓冲区满。
缓冲区满的处理
发送数据(两种选择)
(1)直到缓冲区有剩余空间-阻塞
(2)新发送的数据没有存入缓冲区
接受数据(两种选择)
(1)新数据不被接受
(2)删除缓冲区已有数据,存放新的数据
丢包现象
设置发送/接受缓冲区的大小
if(1) { int bufsize=128*1024; int ret=setsockopt( sock.hSock, SOL_SOCKET, SO_SNDBUF,//SO_RCVBUF (const char *)&bufsize, sizeof(int) ); }
【丢包】
一般情况下设置缓冲区大小并不能解决丢包问题
(1)发送是否均匀
(2)接受是否及时
(3)数据带宽是否已经超过实际传输宽度
另外,即使HostA和HostB处理都没问题,网络上任意一个中间节点设备在转发该包时都有可能丢包。
结论:对UDP来说,丢包“家常便饭”,设计时考虑这一点
【网络字节序】
网络上的数据是一个字节一个字节地串行传输的
"hello"
h->68
e->65
l->6C
l->6C
o->6F
unsigned int a=0x12345678
它在内存的排列
78 56 34 12
规定
规定低字节在前,则称为小端
规定高字节在前,则称为大端
大端与小端是一套(硬件和软件),我们见到的主流都是小端
如intel/AMD,很少有大端系统
【网络传输时】
unsigned int a=0x12345678
如12 34 56 78(大端)
如78 56 34 12(小端)
惯例都是按大端传输
big-endian
一个int型数据占4个字节,下面按大端传输int型数据
【观察】
//HostA #include<iostream> using namespace std; #include "afos/AfSocket.h" void Endian_intToChar(int temp,char bytes[]) { bytes[0]=(char)(temp >> 24); bytes[1]=(char)(temp >> 16); bytes[2]=(char)(temp >> 8); bytes[3]=(char)(temp); } int main() { //发送方 AfSockAddr local("192.168.1.105",9000);//发送方地址 AfUdpSocket soc; soc.Open(local,true); cout<<"发送方-端口9000 ->"<<endl; while (1) { cout<<"please push Enter!"<<endl; getchar();//每按一次回车... AfSockAddr peer("192.168.1.105",9001); char bytes[4]; int temp=0x34560012;//int型数据的传输不再深究 Endian_intToChar(temp,bytes); soc.SendTo(bytes,4,peer); } soc.Close(); return 0; }
//HostB #include<iostream> using namespace std; #include "afos/AfSocket.h" int Endian_CharToInt(char bytes[],int n)//四个字节char转为一个int型数据 { int temp=0; temp+=(bytes[0]<<24); temp+=(bytes[1]<<16); temp+=(bytes[2]<<8); temp+=(bytes[3]); return temp; } int main() { //接受方 AfSockAddr local("192.168.1.105",9001);//AfSockAddr local("192.168.1.104",9001);//接收方地址 AfUdpSocket soc; soc.Open(local,true); cout<<"接收到-端口9001->"<<endl; char buffer[128]; while (1) { AfSockAddr peer; int len=soc.RecvFrom(buffer,128,peer); buffer[len]=‘\0‘; if (len>0) { int temp; temp=Endian_CharToInt(buffer,len); printf("%08x\n",temp); } if (strcmp("quit",buffer)==0) { break; } } soc.Close(); return 0; }
【默认分配的端口号】
【端口的占用】
【多个发送方,一个接收方】
【阻塞与超时】
【1】默认分配的端口号
发送方可以不显示指定端口号
AfUdpSocket soc;
soc.Open();
可以查看自动分配的端口号
AfSockAddr local;
sock.GetLocalAddr(local);
unsigned int port=local.GetPort();
printf("local port:%d\n",port);
注意:在发送数据的时候,才会自动分配端口。
【2】端口的占用
当端口处于占用时,再创建一个Socket,还使用相同的端口,则创建失败,sock.Open()返回-1
一般设为可重用
sock.Open(local,true);//true允许重用,false不允许重用
【3】多个发送方,一个接收方
是谁发来的
string peer_ip=peer.GetIp_str();
int peer_port=peer.GetPort();
printf("from: IP->%s Port->%d",peer_ip.c_str(),peer_port);
【4】阻塞与超时
sock.RecvFrom()缓冲区无数据则等待,即阻塞,可设置最大时间
设置接收超时
sock.SetOpt_RecvTimeout(3000);//毫秒设置接收超时
AfUdpSocket soc;
soc.SetOpt_RecvTimeout(3000);//毫秒设置接收超时
int len=soc.RecvFrom(buffer,128,peer);
if (len<0)
{
printf("got %d\n",len);
}
非阻塞,定时查看(轮训),有数据返回0,无数据返回-1
C++网络Socket