INVALID_SOCKET 无效网络套接字;
在windows上演示需要添加一个库:
::recv(Socket,recvBuf,BUFFERMAXSIZE,0);
第一个参数是建立的socket
第二个参数是用来存储的recv数据的buf
第三个参数是允许最大的接收size而不是buf的size 但是buf的size一定要大于允许最大的接收size
第四个参数是设置recvtimeout用好像是
主要说两点
一是当server发送数据调用send函数时,调用成功只是把该部分数据拷贝到发送缓冲区,接下来的工作是由Tcp/Ip协议发送数据的。
当server端的数据比Client端的数据长时 client端recv时是多包的
len = ::recv(Socket,recvBuf,BUFFERMAXSIZE,0);
if(len == BUFFERMAXSIZE)还可以接着recv直到len < BUFFERMAXSIZE
二是当len= -1时,可能是socket关闭。
还有当建立的是TCP连接时,网络断开是recv是可以检测到的返回len = -1所以不用担心会挂起在recv中。
判断是windows系统还是linux系统:
#ifdef WIN32
#include <WinSock2.h>
#else
//linux
#endif
Socket必备;
1. 要写一个监听的接口:listen:
2. 是否已连接的接口:isConnected;
3. Connect()客户端通过ip连接服务器的接口;
4. 发送数据的接口;send()
5. 是否接收数据的接口;recvStart();
6. 是否接收完了的接口;recvComplete();
7. 接收数据长度的接口:RecvData();
//实现监听listen(shor port);
{
SOCKET sock = socket(AF_INET,SOCK_STREAM,0);//设置为ipv4的流文件传输;
然后做个判断:
If(scok == INVALID_SOCKET) return false;
然后绑定端口:
1. 先写好ip和ip类型和端口;struct
Struct scoketaddr_in addr;//结构体定义;
Addr.family = AF_INET;//协议类型;
Addr.sin_port = htons(port);//端口;
Addr.sin_addr.S_un.S_addr = INADDR_ANY;//ip地址; INADDR_ANY = 0.0.0.0;
2. 开始绑定:
Int ret = bind(sock,(struct sockaddr*)&addr,sizeof(addr));//绑定socket接口和ip地址,和长度;
然后对绑定进行错误判断:
If(ret != 0)
{
Closesocket(sock);
Returnfalse;
}
//监听连接数;
listen(sock,10);
启动socket网络之前先要连接服务器,所以把服务器赋值好;
_server = sock;
//在启动线程之前,让链接判断为0;
_isConnected = 0;
Windows下起线程,;
HANDLE hThread =CreateThread(NULL,0,AcceptThreadFunc,NULL,0,NULL);//创建线程;
CloseHandle(hThread);
Return true;
}
这个现场链接服务器;
//复写线程的函数;
DWORD net::AcceptThreadFunc(void * arg)
{
_connect = accept(_server,NULL,NULL);
//进入这里的时候线程启动,isconnect为1;
_isConnected =1;
//DWORD的返回类型是无符号长整型,unsigned long int;
Return0;
}
//是否链接;
Bool net::isConnected()
{
Return(bool)_isConnected;
}
客户端的socket写法;//服务器的listen监听只有一个端口;short port;
这里是客户端去连服务器,所以要有个对准服务器的ip地址;
Bool net::Connect(const char * ip,shorport)
{
_connect= socket(AF_INET,SOCK_STEAM,0);//协议类型ipv4文件流;
//再来个判断;
If(_connect== INVALID_SOCKET) return false;
//链接的话需要ip地址和端口;
Structsockaddr_in addr;
Addr.sin_family= AF_INET;
Addr.sin_port= htons(port);
Addr.sin_addr.S_un.S_addr= inet_addr(ip);
//connect;
Intret = connect(_connect,(struct sockaddr *)&addr,sizeof(addr));//服务器绑定和客户端连接时一样写的;
If(ret!= 0)
{
Closesocket(_connect);
Return false;
}
//链接成功;
Return false;
}
开始接收数据;
Bool net::RecvStart()
{
//这里调用recvstart会阻塞,所以要用线程,实际程序的接收是在线程里;
_isRecvComplete= 0;
HANDLEhThread = CreateThread(NULL,0,RecvThreadFunc,NULL,0,NULL);//创建线程;
CloseHandle(hThread);
Return true;
}
DWORD net::RecvThreadFunc(void * arg)
{
Staticchar * buf[16];
Recv(_connect,buf,1,0);
…
_recvData = buf;
_isRecvComplete = 1;
Return 0;
}
//数据接收成功;
Bool net::isRecvComplete()
{
Return(bool)_isRecvComplete;
}
Char * net::RecvData(int & len)
{
Len = 0;
_isRecvComplete = 0;
Return _recvData;
}
Int net::Send(const char * buffer,int len)
{
Returnsend(_connect,buffer,len,0);
}
.cpp:
#include "Net.h"
SOCKET Net::_server =INVALID_SOCKET;//INVALID_SOCKET表示无效的socket:
SOCKET Net::_connect = INVALID_SOCKET;
int Net::_isConnected = 0;
int Net::_isRecvComplete = 0;
char * Net::_recvData = NULL;
bool Net::Listen(short port)
{
//写一个SOCKET接口变量附上协议类型;
SOCKETsock = socket(AF_INET, SOCK_STREAM, 0);
//如果协议都错了的话就不让登陆;
if(sock = INVALID_SOCKET){
CCLog("sockfail");
returnfalse;
}
//绑定端口;写地址结构体;
structsockaddr_in addr;
//地址类型IPV4;
addr.sin_family= AF_INET;
//转换端口;
addr.sin_port= htons(port);
//ip地址;
addr.sin_addr.S_un.S_addr= INADDR_ANY;
//绑定地址和协议:
intret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
//绑定失败就返回;
if(ret != 0)
{
//关闭
closesocket(sock);
returnfalse;
}
//系统的监听函数,决定最多监听多少个人的;
listen(sock,10);
//这个位置用accpet的话会阻塞,所以开个线程来干;
//服务端等于这个监听接口;
_server= sock;
//在线程启动之前,让判断为0;
_isConnected= 0;
//写线程执行;第三个参数为线程执行的函数;
HANDLEhThread = CreateThread(NULL, 0, AcceptThreadFunc, NULL, 0, NULL);
//执行完后关闭线程;
CloseHandle(hThread);
returntrue;
}
//服务器端线程的函数;
DWORD Net::AcceptThreadFunc(void *)
{
//链接服务器;就这个是最重要的;
_connect= accept(_server, NULL, NULL);
//设为1 表示线程启动;
_isConnected= 1;
//DWORD类型返回的是无符号长整型:unsignedlong int;
return0;
}
//是否处于已连接状态;
bool Net::isConnected()
{
return(bool)_isConnected;
}
//客户端一边的连接函数;
bool Net::Connect(const char * ip, shortport)
{
//客户端连接服务器;
_connect= socket(AF_INET, SOCK_STREAM, 0);
if(_connect == INVALID_SOCKET)
{
returnfalse;
}
//要求连接的话需要些地址,ip地址结构体:
structsockaddr_in addr;
addr.sin_family= AF_INET;
addr.sin_port= htons(port);
addr.sin_addr.S_un.S_addr= inet_addr(ip);//<-写地址的方式传入;
//有地址的话就可以连接了:
intret = connect(_connect, (struct sockaddr *)&addr, sizeof(addr));
//错误判断;
if(ret != 0)
{
closesocket(_connect);
returnfalse;
}
//连接成功,游戏就开始了;不过这里专门处理连接,就不在这里写了;
returntrue;
}
bool Net::RecvStart()
{
//这里调用recvStart会阻塞,所以要用线程,实际接收都是在线程里的:
_isRecvComplete= 0;//为0则可以接收;
//创建线程,线程里执行完后就关闭线程;
HANDLEhThread = CreateThread(NULL, 0, RecvThreadFunc, NULL, 0, NULL);
CloseHandle(hThread);
returntrue;
}
DWORD Net::RecvThreadFunc(void * arg)
{
staticchar buf[16];
//系统函数,sock,接收数据buf,接收长度,链接超时;
recv(_connect,buf, 16, 0);
_recvData= buf;//接收数据等于buf;
_isRecvComplete= 1;//接收成功后等于1,停止接收;
return0;
}
//是否已经接收成功;
bool Net::isRecvComplete()
{
return(bool)_isRecvComplete;
}
//获取数据,len没用,多比少好;
char * Net::RecvData(int &len)
{
len= 0;//len没用;
//报文取走,那么报文就要回到没有用的状态;
_isRecvComplete= 0;
return_recvData;
}
//向客户端发送数据;
int Net::Send(const char * buffer, int len)
{
returnsend(_connect, buffer, len, 0);
}
.h:
#ifndef __Net_H__
#define __Net_H__
#include "cocos2d.h"
//如果是windows下的话要写这个;
#ifdef WIN32
#include <WinSock2.h>
#else
//linux
#endif
//网络接口;
#include "cocos2d.h"
USING_NS_CC;
class Net
{
public:
//1.定义socket;要是静态的;
staticSOCKET _server;//服务器;
staticSOCKET _connect;//客户端连接服务器;
//传一个变量表示连接状态:
staticint _isConnected;
staticint _isRecvComplete;
//传数据;
staticchar * _recvData;
//监听函数接口:
staticbool Listen(short port = 9999);
//是否已连接状态;
staticbool isConnected();
//客户端去连接:
staticbool Connect(const char * ip, short port = 9999);
//发送数据:
staticint Send(const char * buffer, int len);
//接收数据:
staticbool RecvStart();
//是否已经成功接收数据:
staticbool isRecvComplete();
//告诉接收有多长:
staticchar * RecvData(int & len);
//接收不是对外的接口:
staticbool Accept();
//线程调用函数:WINAPI表示一个特殊的接口,是win32的东西,返回类型是DWORD无符号长整型;
staticDWORD WINAPI AcceptThreadFunc(void * arg);
staticDWORD WINAPI RecvThreadFunc(void * arg);
};
#endif