实现的单个socket例子,了解socket原理。

先创建一个win32的项目(命令行的),作为服务端

// SocketServer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
const int BUF_SIZE = 64;
WSADATA wsd; //wsdata 变量
SOCKET sServer; //服务器套接字
SOCKET sClient; //客户端套接字
SOCKADDR_IN addrServ; // 服务器地址
char buf[BUF_SIZE]; //接受数据缓存区
char sendBuf[BUF_SIZE]; //返回给客户端数据
int retVal; //返回值

//初始化套接字动态库
if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)
{
cout << "wsastartup failed!" <<endl;
return 1;
}
//创建套接字
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(INVALID_SOCKET == sServer)
{
cout << "socket failed" <<endl;
WSACleanup();//释放套接字
return -1;
}

//服务器套接字地址
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(4999);
addrServ.sin_addr.s_addr = INADDR_ANY;

//绑定套接字
retVal = bind(sServer,(LPSOCKADDR)&addrServ,sizeof(SOCKADDR_IN));
if(SOCKET_ERROR == retVal)
{
cout << "bind failed" <<endl;
closesocket(sServer);//关闭套接字
WSACleanup();
return -1;
}
//开始监听
retVal = listen(sServer,1);
if(SOCKET_ERROR == retVal)
{
cout << "listen failed" <<endl;
closesocket(sServer);
WSACleanup();
return -1;
}
cout << "开始监听,请链接..." << endl;

//接受客户端请求
sockaddr_in addrClient;
int addrClientlen = sizeof(addrClient);
sClient = accept(sServer,(sockaddr FAR*)&addrClient, &addrClientlen);
if(INVALID_SOCKET == sClient)
{
cout << "accept failed!" <<endl;
closesocket(sServer);//关闭套接字
WSACleanup();
return -1;
}
cout << "客户端链接成功..." << endl;
while (true)
{
//接受客户端数据
ZeroMemory(buf, BUF_SIZE);
retVal = recv(sClient, buf, BUF_SIZE, 0);
if(SOCKET_ERROR == retVal)
{
closesocket(sServer);//关闭套接字
closesocket(sClient);//关闭套接字
WSACleanup();
return -1;
}
if(buf[0] == '0')
break;

cout << "客户端发送的数据:" << buf <<endl;
cout << "向客户端发送数据";
cin>>sendBuf;
send(sClient,sendBuf,strlen(sendBuf), 0);
}

closesocket(sServer);
closesocket(sClient);
WSACleanup();

return 0;
}

再创建一个项目作为客户端,

// SocketClient.cpp : 定义控制台应用程序的入口点。
//客户端
//

#include "stdafx.h"
#include "winsock2.h"
#include <iostream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;

BOOL RecvLine(SOCKET s, char *buf);//读取一行数据

int _tmain(int argc, _TCHAR* argv[])
{
const int BUF_SIZE = 64;
WSADATA wsd; //WSADATA变量
SOCKET sHost; //服务器套接字
SOCKADDR_IN servAddr; //服务器地址
char buf[BUF_SIZE]; //
char bufRecv[BUF_SIZE];
int retVal;

//初始化套接字动态
if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)
{
cout << "WSAStartup failed" << endl;
return -1;
}

//创建套接字
sHost = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
if(INVALID_SOCKET == sHost)
{
cout << "socket failed" <<endl;
WSACleanup();
return -1;
}
//设置服务器地址
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servAddr.sin_port = htons((short)4999);
int nServAddlen = sizeof(servAddr);

//连接服务器
cout<< "连接服务器" << endl;
retVal = connect(sHost,(LPSOCKADDR)&servAddr, nServAddlen);
if(retVal == SOCKET_ERROR)
{
cout << "connect failed" << endl;
closesocket(sHost);
WSACleanup();
return -1;
}
cout<< "connect success" << endl;
while (true)
{
//向服务器发送数据
ZeroMemory(buf, BUF_SIZE);
cout << "向服务器发送数据:" ;
cin >> buf;
retVal = send(sHost,buf, strlen(buf),0);
if(retVal == SOCKET_ERROR)
{
cout << "send failed" << endl;
closesocket(sHost);
WSACleanup();
return -1;
}
recv(sHost, bufRecv, 5,0);//接受服务器数据,只接5个字符
cout << endl << "从服务器接受数据:" << bufRecv;
}
//退出
closesocket(sHost);
WSACleanup();
system("pause");
return 0;
}

然后运行服务端,运行客户端,之间进行通信。

备注:

创建套接字的函数是socket(),函数原型为:

#include <sys/types.h>
  #include <sys/socket.h>
     int socket(int domain, int type, int protocol);

其中“int domain”参数表示套接字要使用的协议簇,协议簇的在“linux/socket.h”里有详细定义,常用的协议簇:

  • AF_UNIX(本机通信)
  • AF_INET(TCP/IP – IPv4)
  • AF_INET6(TCP/IP – IPv6)

其中“type”参数指的是套接字类型,常用的类型有:

  • SOCK_STREAM(TCP流)
  • SOCK_DGRAM(UDP数据报)
  • SOCK_RAW(原始套接字)

最后一个“protocol”一般设置为“0”,也就是当确定套接字使用的协议簇和类型时,这个参数的值就为0,但是有时候创建原始套接字时,并不知道要使用的协议簇和类型,也就是domain参数未知情况下,这时protocol这个参数就起作用了,它可以确定协议的种类。

socket是一个函数,那么它也有返回值,当套接字创建成功时,返回套接字,失败返回“-1”,错误代码则写入“errno”中。

创建套接字:

#include <sys/types.h>
   #include <sys/socket.h>
   #include <linux/socket.h>
     int sock_fd_tcp;
     int sock_fd_udp;
     sock_fd_tcp = socket(AF_INET, SOCK_STREAM, 0);
     sock_fd_udp = socket(AF_INET, SOCK_DGRAM, 0);
     if(sock_fd_tcp < 0){
          perror("TCP SOCKET ERROR!\n");
          exit(-1);
     }
 
     if(sock_fd_udp < 0){
          perror("UDP SOCKET ERROR!\n");
          exit(-1);
     }

什么是Socket?举一个例子:Lewis跟Nico两人聊QQ,QQ是一个独立的应用程序,那么它对应了两个Socket,一个在Lewis的电脑上,一个在Nico的电脑上。当Lewis对Nico说:”周末我们去开卡丁车吧!“,这句话就是一段数据,这段数据会先储存在Lewis电脑Socket上,我们在”分层网络模型“一文中提到过,TCP存在于传输层,同时,我们在”端口、IP协议“一文中又提到了TCP传输过程(三次握手建立连接,三次握手关闭连接),当Lewis的QQ和Nico的QQ连接成功后,Lewis的Socket将这段话的数据发送到Nico的电脑中,但是Nico暂时还没看到,因为数据会先存放在Nico电脑的Socket当中,然后Socket会把数据呈现给Nico看。

到了这里不禁要问,数据传送过程中为什么要多出Socket这样东西?

答:因为不同的应用程序对应不同的Socket,而Socket保证了QQ的数据不会到处乱跑,不会一冲动跑到MSN上去了。因为QQ和MSN两个应用程序的Socket内容是完全不同的。那么Socket里面到底是什么?

答:Socket套接字地址!套接字地址是一个数据结构,我们仅基于TCP传输协议作为例子。套接字地址这个数据结构里面包含了:地址类型、端口号、IP地址、填充字节这4种数据。而它的数据结构原型为:

#include <netinet/in.h>
    struct sockaddr_in{
     unsigned short         sin_family;    
     unsigned short int     sin_port;      
     struct in_addr         sin_addr;      
     unsigned char          sin_zero[8];   
  };

其中:

  • sin_family表示地址类型,对于基于TCP/IP传输协议的通信,该值只能是AF_INET;
  • sin_prot表示端口号,例如:21 或者 80 或者 27015,总之在0 ~ 65535之间;
  • sin_addr表示32位的IP地址,例如:192.168.1.5 或 202.96.134.133;
  • sin_zero表示填充字节,一般情况下该值为0;

Socket数据的赋值实例:

struct sockaddr_in Lewis;
  Lewis.sin_family      = AF_INET;
  Lewis.sin_port        = htons(80);
  Lewis.sin_addr.s_addr = inet_addr("202.96.134.133");
  memset(Lewis.sin_zero,0,sizeof(Lewis.sin_zero));

分析:我们设置了一个名叫Lewis的套接字地址,它基于TCP/IP协议,因此sin_family的值为AF_INET,这个是雷打不动的,只要使用TCP/IP协议簇,该值就是AF_INET;htons是端口函数,以后介绍,这就表示设置了端口号为80;

sin_addr是一个数据结构,原型是:

struct in_addr{
     unsigned long     s_addr;
};

因此,Lewis这个套接字地址的IP赋值格式是Lewis.sin_addr.s_addr,inet_addr函数也是日后再说,这里表示设置IP地址为202.96.134.133;而memset函数在这里起到给sin_zero数组清零的作用,它的原型是:

memset(void *s, int c, size_t n);

int listen( SOCKET s, int backlog);
第2个参数,是侦听队列的长度,也就是同时接受连接的个数,不是已经连接socket的个数
也就是listen接收到了连接,还没使用accpet来创建的连接,
比如设置为5,你接收到了5个请求,但是都没用accept来创建连接,则,第6个人连接你的时候,会连不上. 只有你调用因此accept创建一个连接,则队列里的个数减1,则又可以接受一个新连接了,第6个人就可以请求连接了.
listen只是监测连接请求(维护一个队列),accept才是真正创建请求 backlog 用于在TCP层接收链接的缓冲池的最大个数,这个个数可在应用层中的listen函数里设置,当客户链接请求大于这个个数(缓冲池满),其它的未进入链接缓冲池的客户端在tcp层上tcp模块会自动重新链接,直到超时(大约57秒后)   
  2)应用层链接(connect)完成时,要从tcp层的链接缓冲池中移出一个(accept函数实现) 3.backlog是连接请求队列的最大长度
  1.在WinSock1.1中最大值5。如果backlog小于1,则backlog被置为1;若backlog大于SOMAXCONN(定义在winsock.h中,值为5),则backlog被置为SOMAXCONN。   
  2.在WinSock2中,没有制定具体值,它由服务提供者决定   
  3.有时候backlog设置很小,这时我们接进多少台机器都没问题是因为服务器机器处理速度很快队列来不及填满就处理完了,而且在同一个时刻到来的连接还是很少的 参考:http://topic.csdn.net/t/20021112/10/1168603.html

参考:

http://blog.csdn.net/my2005lb/article/details/8689408

http://www.himigame.com/iphone-cocos2dx/844.html

coco2dx服务器简单例子的更多相关文章

  1. AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答

    一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...

  2. [转] 3个学习Socket编程的简单例子:TCP Server/Client, Select

    以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序.如果你能完全理解这3个例子,估计 ...

  3. java 使用 comet4j 主动向客户端推送信息 简单例子

    [背景] 今天,一个前端的师弟问我怎样做实时聊天窗口,我毫不犹豫地说:在前台定时访问服务端呀!师弟默默地百度了一番,最后告诉我,有一种技术是后服务端动推送信息给客户端的,这种技术的名字叫comet,我 ...

  4. 使用git代替FTP部署代码到服务器的例子

    这篇文章主要介绍了使用git代替FTP部署代码到服务器的例子,这种方法可以节省流量.节省时间,需要的朋友可以参考下 本地开发完成后,通常会在服务器上部署,有人会使用ftp,有人会使用scp, ftp和 ...

  5. 老司机实战Windows Server Docker:4 单节点Windows Docker服务器简单运维(下)

    上篇中,我们主要介绍了使用docker-compose对Windows Docker单服务器进行远程管理,编译和部署镜像,并且设置容器的自动启动.但是,还有一些重要的问题没有解决,这些问题不解决,就完 ...

  6. 关于c#邮件发送的简单例子

    这里所说的发送邮件,以发送qq邮件为例. 首先我们先要在自己的邮箱配置好如下选项:

  7. Spark简介安装和简单例子

    Spark简介安装和简单例子 Spark简介 Spark是一种快速.通用.可扩展的大数据分析引擎,目前,Spark生态系统已经发展成为一个包含多个子项目的集合,其中包含SparkSQL.Spark S ...

  8. 使用 CXF 做 webservice 简单例子(转载)

    使用 CXF 做 webservice 简单例子     Apache CXF 是一个开放源代码框架,提供了用于方便地构建和开发 Web 服务的可靠基础架构.它允许创建高性能和可扩展的服务,您可以将这 ...

  9. delphi 三层架构简单例子(经测试成功)

    delphi 三层架构简单例子(经测试成功) 转载 2013年12月19日 09:48:57 1100 所谓三层: (1) 客户端 (2) 服务器端 (3) 数据库 在数据访问时,使得客户端必须通过服 ...

随机推荐

  1. ios9 升级后 企业版app plist无法安装

    昨天apple推送了ios9, 公司的一些app是企业版的,平常通过 item-service 结果更改如下 plist可以了 itms-services://?action=download-man ...

  2. Oracle Flashback Technologies (总)

    Oracle Flashback Technologies Oracle 9i中增加了闪回查询技术,闪回查询为数据库提供了一种简单.强大.完全无干扰从人为错误中恢复的机制.通过闪回查询,用户可以查看过 ...

  3. Java-NIO-Selector

    扩展阅读: Java NIO类库Selector机制解析(上) Java NIO类库Selector机制解析(下) Java NIO的选择器 三个重要的类: 1,Selector 选择器,完成主要的选 ...

  4. C++Primer 第九章

    //1.vector:可变大小数组.支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢.注意点:不要在vector中存放bool类型,vector<bool>并不是一个容器,其实现方 ...

  5. Website English Comments

    幻灯新闻下方的广告 Slide news at the bottom of the advertisement 人才招聘 recruitment 左/右侧推荐区 The left/right side ...

  6. G面经prepare: Data Stream Average

    给一个datastream和一个fixed window size, 让我design一个class可以完成add number还有find average in the window. 就是不能用v ...

  7. Struts2配置文件各种标签的含义

    最近正在学习Struts2,在配置文件中遇到好多标签,各种意义不同.为了方便学习,便把各种标签的书写和含义总结如下:(随时更新)   <struts>     <!-- 开启使用开发 ...

  8. Codeforce Round #210 Div2

    A:对角线为k其他为0 B:利用两个相邻的数一定gcd为1和1与任何数gcd为1错k个位就行了 C:不会做操蛋,好像是因为上一层的始终小于下一层的 好吧C又研究了一下,是个贪心题,不符合的情况先科不考 ...

  9. 转:python webdriver API 之上传文件

    文件上传操作也比较常见功能之一,上传功能操作 webdriver 并没有提供对应的方法,关键上传文件的思路.上传过程一般要打开一个系统的 window 窗口,从窗口选择本地文件添加.所以,一般会卡在如 ...

  10. Android中操作数据的集中方式---文件,SQLite,ContentProvider

    http://blog.csdn.net/he90227/article/details/33734239 转