socket编程我用的就是原生态的socket,今天也只是学了下原理,写了一个简单的小例子,听说websocket这个第三方库不错,这几天也想学学,看看怎么样吧。原生态的socket我第一次弄,中间出了不少的问题,我把他们都记录了下来,方便以后看吧。明天想移植到android上看看,解决一下编码的问题库的问题什么的,今天把他们的使用方法贴出来,大家可以参考一下。

#include "HelloWorldScene.h"
//需要包含目录E:\cocos2d-x-2.2\cocos2d-x-2.2\cocos2dx\platform\third_party\win32\pthread
#include "pthread.h"

//需要加入库ws2_32.lib
//在不同的平台下引入不同的头文件
#if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
	#ifndef _WINSOCKAPI_
	#define _WINSOCKAPI_
		#ifndef _WINSOCK2API
		#define _WINSOCK2API
			#include <WinSock2.h>
		#endif
	#endif
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>

#endif

typedef unsigned int SOCKET;

以上的代码是在头文件中的申明,这里要注意不同的平台需要包含不同的头文件,thread头文件还要附加包含路径,socket要引入库。

//服务器端的代码
void HelloWorld::initSocket()
{
	//在windows下要初始化socket库,以下代码本人也不知道含义,不过照抄好了
	#if(CC_TARGET_PLATFORM==CC_PLATFORM_WIN32)
		WORD wVersionRequested;
		WSADATA wsaData;
		int err;
		wVersionRequested=MAKEWORD(1,1);
		err=WSAStartup(wVersionRequested,&wsaData);
		if(err!=0){
			return;
		}
		if(LOBYTE(wsaData.wVersion)!=1 || HIBYTE(wsaData.wVersion)!=1){
			WSACleanup();
			return;
		}
	#endif

	//1、定义一个socket
	//AF_INET ipv4协议 第二个参数代表是TCP通信还是UDP通信
	//SCOK_STREAM是TCP通信,SCOK_DGRAM是UPD通信,第三个参数填0
	//返回socket描述符,失败返回-1
	SOCKET sockid = socket(AF_INET,SOCK_STREAM,0);
	if(sockid == -1)
	{
		CCLog("socket error");
		this->errorCode(sockid);
		return;
	}

	CCLog("%d",sockid);

	//2 定义通信地址结构体
	struct sockaddr_in sockaddr;
	//使用ipv4协议族
	sockaddr.sin_family = AF_INET;
	 //htons将主机字节序转化为网络字节序,网络字节序统一采用大端格式,而有的主机使用的是小端模式
	//所以要进行转换,sin_port代表的是端口号
	sockaddr.sin_port = htons(8888);
	//想要通信的网络地址
	//inet_addr()将一个以.分割的字符串转化为一个网络地址
	sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	//以下这句话表示的就是本机的IP地址
	//sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);

	 //3 将socket和通信地址结构体绑定
	if(bind(sockid,(struct sockaddr *)&sockaddr,sizeof(struct sockaddr_in)) == -1)
	{
		//如果失败的话,根据不同的平台做不同的处理
		CCLog("bind is error!");
		this->errorCode(sockid);
		return;
	}

	//4 监听 第二个参数设置请求排队的最大长度
	//也就是说同一时刻有多个客户端程序可以和服务端相连, 使用这个表示可以接受的排队长度.
	if(listen(sockid,100) == -1)
	{
		CCLog("listen");
		this->errorCode(sockid);
		return;
	}

	CCLog("everying is ok! and accepting");

	//一个死循环,用来不断接收多个客户端的请求
	while(1)
	{
		struct sockaddr_in sockaddr_from;
		int  len = sizeof(sockaddr_from);
		 //accept调用时,服务器端的程序会一直阻塞,直到有一个
		//客户程序发出了连接,这里边的参数和bind函数的参数类似,后俩个参数是用来接受信息的
		//这里要特别的注意,我让这个问题搞了俩个小时了,就是应该用client_socket接受accept返回的值
		//这个值是用来和客户端通信的socket!
		SOCKET client_socket;
		if((client_socket = accept(sockid,(struct sockaddr *)&sockaddr_from,&len)) == -1)
		{
			CCLog("accept error");
			this->errorCode(sockid);
			return;
		}
		//打印客户端的信息
		CCLog("client %s accepted! port is %d",inet_ntoa(sockaddr_from.sin_addr),
			ntohs(sockaddr_from.sin_port));

		//创建一个线程,用来处理客户端的请求
		pthread_t pthread_id;
		pthread_create(&pthread_id,NULL,HelloWorld::doSomthing,(void *)client_socket);
		char * a[1];
		pthread_join(pthread_id,(void **)a);
	}
}

//处理客户端请求的操作写在这里
void * HelloWorld::doSomthing(void * sock)
{
	SOCKET sockid = (SOCKET)sock;
	CCLog("%d",sockid);
	char buf[10];
	int len;
	//最后一个参数一般设置为0
	len = recv(sockid,buf,sizeof(buf),0);
	if(-1 != len)
	{
		//将客户端的数据打印出来
		CCLog("%d",len);
		CCLog("%s",buf);
	}
	else
	{
		CCLog("recv failed!");
		pthread_exit((void *)-1);
	}

	return 0;
}

//socket不成功调用的失败代码
void HelloWorld::errorCode(SOCKET sockid)
{
#if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
		closesocket(sockid);
		WSACleanup();
#else
		close(sockid);
#endif
		return;
}
//客户端代码
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
	//在windows下要初始化socket库,以下代码本人也不知道含义,不过照抄好了
	#if(CC_TARGET_PLATFORM==CC_PLATFORM_WIN32)
		WORD wVersionRequested;
		WSADATA wsaData;
		int err;
		wVersionRequested=MAKEWORD(1,1);
		err=WSAStartup(wVersionRequested,&wsaData);
		if(err!=0){
			return;
		}
		if(LOBYTE(wsaData.wVersion)!=1 || HIBYTE(wsaData.wVersion)!=1){
			WSACleanup();
			return;
		}
	#endif

	SOCKET sockid = socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in sockaddr;
	sockaddr.sin_family = AF_INET;
	//地址需要写服务器端的地址
	sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	//端口号和服务器的端口号相同
	sockaddr.sin_port = htons(8888);
	int len = sizeof(struct sockaddr_in);

	//客户端使用的函数是connect()
	if(connect(sockid,(struct sockaddr *)&sockaddr,len) == -1)
	{
		CCLog("accept error");
		#if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
				closesocket(sockid);
				WSACleanup();
		#else
				close(sockid);
		#endif
		return;
	}
	CCLog("client connect is ok!");
	static int i = 1;
	CCString * str = CCString::createWithFormat("%d client",i++);
	//最后一个参数写0就可以了
	int len2 = send(sockid,str->getCString(),str->length(),0);
	if(len2 != -1)
	{
		CCLog("send %d bytes",len2);
	}
	else
	{
		CCLog("send failure!");
	}
}

以上代码的含义我注释的已经非常清楚了,有不懂的可以问我,对于线程的那部分可以看看我以前的文章。在这个过程中我也走了不少的歪路,希望我们共同学习!

socket编程解决网络数据的传输