vivox3玩游戏怎么样
804 2023-08-01 14:07:11
tcp/ip协议是双工的。所谓双工,就是发送与接收可以同时进行。你当然可以send两次,但receive的情况是未知的,可能是一次,也可能是2次--当第一次发送完后缓冲区充满时。
使用socket编成,准确地说,使用tcp/ip协议编程时,务必要注意,无论是发送,还是接收,都不是接口能够控制的------tcp/ip协议将在内部完成这一任务。接口提供的send方法只能将数据写入本地的缓冲区,而receive方法只能读取本地缓冲区的数据。
直接用心跳就可以了。
解释下:由服务器周期性的给客户端发送消息,客户端
收到后回复(表示客户端还活着)。
当然了,频率和周期可以自己设定,不管是回复超时还是
出错等等,都可以记录失败次数,到达一定的次数就可以
断定客户端掉了。
这可是我自己总结的,LZ不要误会哦~~!
1.简单服务器
//#include 《winsock2.h》
//#pragma comment(lib,“WS2_32.lib“)
WSADATA sServer,sClient;
chat buf;
int retVal;
if(WSAStartup(MAKEWORD(2,2),&wsd)!=0)
{
return -1;//失败
}
sServer=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET==sServer)
{
WSACleanup();
return -1;//创建套接字失败
}
SOCKADDR_IN addrServ;
addrServ.sin_family=AF_INET;
addrServ.sin_port=htons(%%1);
addrServ.sin_addr.s_addr=INADDR_ANY;
retVal=bind(sServer,(LPSOCKADDR)&addrServ,sizeof(SOCKADDR_IN));
if(SOCKET_ERROR==retVal)
{
closesocket(sServer);
WSACleanup();
return -1;//绑定套接字失败
}
retVal=listen(sServer,1);
if(SOCKET_ERROR==retVal)
{
closesocket(sServer);
WSACleanup();
return -1;//开始监听失败
}
socketaddr_in addrClient;
int addrClientlen=sizeof(addrClient);
sClient=accept(sServer(sockaddr FAR*)&addrClient,&addClientlen);
if(INVALID_SOCKET==sClient)
{
closesocket(sServer);
WSACleanup();
return -1;//开始接受客户端连接失败
}
ZeroMemory(buf,sizeof(buf));
retVal=recv(sClient,buf,sizeof(buf));
if(SOCKET_ERROR==retVal)
{
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return -1;//接收数据失败
}
CString %%2(buf);
closesocket(sServer);
closesocket(sClient);
WSACleanup();
2.简单客户端
//#include 《winsock2.h》
//#pragma comment(lib,“WS2_32.lib“)
WSADATA sHost;
SOCKADDR_IN addrServ;
chat buf;
int retVal;
if(WSAStartup(MAKEWORD(2,2),&wsd)!=0)
{
return -1;//失败
}
sHost=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET==sHost)
{
WSACleanup();
return -1;//创建套接字失败
}
servAddr.sin_family=AF_INET;
servAddr.sin_addr.s_addr=inet_addr(%%1);
servAddr.sin_port=htons((short)%%2);
int nServAddlen=size(servAddr);
retVal=connect(sHost,(LPSOCKADDR)&servAddr,sizeof(servAddr));
if(sOCKET_ERROR==retVal)
closesocket(sHost);
WSACleanup();
return -1;//连接服务器失败
}
ZeroMemory(buf,sizeof(buf));
strcpy(buf,%%3);
retVal=send(sHost,buf,sizeof(buf),0);
if(SOCKET_ERROR==retVal)
{
closesocket(sHost);
WSACleanup();
return -1;//向服务器发送数据失败
}
closesocket(sHost);
WSACleanup();
3.获得本机IP
//#include 《winsock2.h》
//#pragma comment(lib,“WS2_32.lib“)
/*
if(WSAStartup(MAKEWORD(2,2),&wsd)!=0)
{
return -1;//失败
}
*/
//#pragma comment(lib,“WS2_32.lib“)
char szHostname,szHostaddress;
if(gethostname(szHostname,info(szHostname))!=SOCKET_ERROR)
{
HOSTENT *pHostEnt=gethostbyname(szHostname);
if(pHostEnt!=NULL){
sprintf(szHostaddress,“%d.%d.%d.%d“,
( pHostEnt-》h_addr_list&0x00ff ),
( pHostEnt-》h_addr_list&0x00ff ),
( pHostEnt-》h_addr_list&0x00ff ),
( pHostEnt-》h_addr_list&0x00ff ));
}
}
else
return;
CString %%1(szHostaddress);
对同一个端口连续多次发送数据时,会将这些数据视为一个数据。也就是说,把它们按照发送顺序连接在一起。
即可接收方最终获得的是整个数据。
例如发送abcdef和girklmn两个数据
接收方就得到abcdefgirklmn。
receive函数返回他送接收到的数据加上一个表示操作状态的字符串。当主机断开连接时,我们退出循环。
看receive的说明
http://w3.impa.br/~diego/software/luasocket/tcp.html
Receive 方法将数据读入 buffer 参数,并返回成功读取的字节数。 从面向连接的套接字和无连接套接字中都可以调用 Receive。
此重载仅要求您提供接收缓冲区。 缓冲区偏移量的默认值为 0,缓冲区的默认大小为缓冲区参数的长度,而 SocketFlags 的默认值为 None。
如果您使用的是面向连接的协议,则在调用 Receive 之前,必须调用 Connect 以建立远程主机连接,或者调用 Accept 以接受传入的连接。 Receive 方法只读取在 Connect 或 Accept 方法中建立的远程主机发送的数据。 如果您使用的是无连接协议,则您也可以使用ReceiveFrom 方法。 ReceiveFrom 将允许您收到从任何主机传入的数据。
如果没有可读取的数据,则 Receive 方法将一直处于阻止状态,直到数据可用,除非使用 Socket.ReceiveTimeout 设置了超时值。 如果超过超时值,Receive 调用将引发 SocketException。 如果您处于非阻止模式,并且协议堆栈缓冲区中没有可用的数据,则 Receive 方法将立即完成并引发 SocketException。 您可以使用 Available 属性确定是否有数据可以读取。 如果 Available 为非零,请重试接收操作。
如果当前使用的是面向连接的 Socket,那么 Receive 方法将会读取所有可用的数据,直到达到缓冲区的大小为止。 如果远程主机使用 Shutdown 方法关闭了 Socket 连接,并且所有可用数据均已收到,则 Receive 方法将立即完成并返回零字节。
如果您使用的是无连接 Socket,则 Receive 将从您在 Connect 方法中指定的目标地址处读取第一个排队的数据报。 如果您接收到的数据报大于 buffer 参数的大小,则 buffer 将用消息的第一部分填充,多余的数据都会丢失,并且会引发 SocketException
public static int SendReceiveTest1(Socket server)
{
byte msg = Encoding.UTF8.GetBytes(“This is a test“);
byte bytes = new byte;
try
{
// Blocks until send returns.
int i = server.Send(msg);
Console.WriteLine(“Sent {0} bytes.“, i);
// Get reply from the server.
i = server.Receive(bytes);
Console.WriteLine(Encoding.UTF8.GetString(bytes));
}
catch (SocketException e)
{
Console.WriteLine(“{0} Error code: {1}.“, e.Message, e.ErrorCode);
return (e.ErrorCode);
}
return 0;
}
这个不难,bytes = temp.Receive(recvBytes, recvBytes.Length, 0);是说接收长度为recvBytes.Length的数据并将数据放进recvBytes中。bytes表示通过套接字一次接收的数据长度。
temp.Send(bs, bs.Length, 0);是说发送长度为bs.Length的bs中的数据。
参数0表示指定的传输控制方式,0就表示没有特殊行为。
recv是socket编程中最常用的函数之一,在阻塞状态的recv有时候会返回不同的值,而对于错误值也有相应的错误码,分别对应不同的状态,下面是我针对常见的几种网络状态的简单总结。 首先阻塞接收的recv有时候会返回0,这仅在对端已经关闭TCP连接时