WinsockPragramming(1) Server(C++版)
2015-05-31 13:44
375 查看
预准备:
在VC中连接动态链接库WS2_32.DLL(所有Winsock函数均从该库导出)。具体做法:“工程”——>“设置”——>“对象/库模块”,添加“WS2_32.DLL”。
创建服务器流程
1、初始化套接字库
调用函数WSAStartup(),函数原型:
int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
函数调用成功返回0。
参数wVersionRequested表示当前套接字库的版本号。
WORD wVersionRequested=MAKEWORD(2,0);
表示版本号为2.0
参数lpWSAData是指向结构体WSADATA的指针变量,表示获取到的套接字库的详细信息。
WSADATA结构体定义原型:
typedef struct WSAData{
WORD wVersion;//库文件建议用用程序使用套接字版本
WORD wHighVersion;//库文件支持的最高版本
char szDescription[WSADESCRIPTION_LEN+1];//描述库文件的字符串
char szSystemStatus[WSASYS_STATUS_LEN+1];//系统状态字符串
unsigned short iMaxSockets;//同时支持的最大套接字数
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
}
初始化套接字库代码:
2、创建套接字句柄
调用函数socket(),函数原型:
SOCKET socket(int af,int type,int protocol);
参数af指定套接字所使用的地址格式
参数type指定套接字类型
SOCK_STREAM 创建流式套接字(基于TCP)
SOCK_DGRAM 创建数据报套接字(基于UDP)
SOCK_RAW 创建原始套接字
参数protocol:如果参数type已经指定套接字类型为TCP或UDP,则该参数可以置为0.
创建套接字句柄代码:
3、地址结构设置及字节顺序转换
此时我们必须了解两个概念:寻址方式和字节顺序。
寻址方式:套接字在各种协议中使用,所以为了区分网络协议,需设定寻址方式。TCP/IP地址中使用IP地址和端口号确定通信双方。
套接字地址结构定义:
struct sockaddr_in{
short sin_family;//指定地址家族(设置为AF_INET表示应用使用的是TCP/IP)
unsigned short sin_port;//指定端口号
struct in_addr sin_addr;//IP地址
char sin_zero[8];//留做备用,需要指定为0
};
sin_addr表示32位的IP地址结构,定义如下:
struct in_addr{
union{
struct{
unsigned char s_b1,s_b2,s_b3,s_b4;
}S_un_b;//用4个u_char字符描述IP地址
struct{
unsigned short s_w1,s_w2;
}S_un_w;//用两个u_short类型描述IP地址
unsigned long S_addr;//用一个u_long类型描述IP地址
}S_un;
};
通常我们使用1个u_long类型字符描述IP地址。
sockaddr_in addr;
addr.sin_addr.S_un.S_addr=inet_addr(“210.6.132.5”);
字节顺序
在Socket编程中,传输数据的排列顺序以网络字节顺序和主机字节顺序为主。主机向网络发送数据,需要把主机字节数据转化为网络字节顺序;主机接收网络发来的数据时,需要把网络字节顺序转化为主机字节顺序。从数据存储角度来看,网络字节顺序先存储最重要的字节,而主机字节顺序先存储不重要的字节。
在进行字节顺序转换时,会用到字节顺序转换函数
u_short htons(u_short hostshort);//将一个u_short类型IP地址从主机字节顺序转换为网络字节顺序
u_long htonl(u_long hostlong);//将一个u_long类型IP地址从主机字节顺序转换为网络字节顺序
u_long ntohl(u_long netlong);//将一个u_long类型IP地址从网络字节顺序转换为主机字节顺序
u_short ntohs(u_short netshort);//将一个u_short类型IP地址从网络字节顺序转换为主机字节顺序
unsigned long inet_addr(const char FAR*cp);//将一个字符串IP转换成以网络字节顺序排列的IP
char FAR*inet_ntoa(struct in_addr in);//讲一个以网络字节顺序排列的IP地址转换成一个字符串IP
地址结构设置及字节顺序转换代码:
4、绑定地址信息
调用bind()函数,其函数原型:
int bind(SOCKET s,const struct sockaddr FAR* name,int namelen);
函数调用成功则返回0。
绑定地址信息代码:
5、监听套接字(仅用于流式套接字)
调用listen()函数,其原型为:
int listen(SOCKET s,int backlog);
参数backlog指定监听的最大连接数。
监听套接字代码:
6、接收客户端连接请求
客户端调用connect()函数发送连接请求,服务器调用accept()接收该请求。accept()函数原型:
SOCKET accept(SOCKET s,struct sockaddr FAR* addr,int FAR* addrlen);
接收客户端连接请求代码:
7、数据收发
调用send()函数和recv()函数,原型:
int send(SOCKET s,const char FAR *buf,int len,int flags);
int recv(SOCKET s,char FAR *buf,int len,int flags)
参数buf是指向数据缓冲区的指针变量,参数flags通常设置为0.
数据收发代码:
8、关闭套接字。
关闭套接字代码
9、释放套接字库
释放套接字库
完整源码:
在VC中连接动态链接库WS2_32.DLL(所有Winsock函数均从该库导出)。具体做法:“工程”——>“设置”——>“对象/库模块”,添加“WS2_32.DLL”。
创建服务器流程
1、初始化套接字库
调用函数WSAStartup(),函数原型:
int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
函数调用成功返回0。
参数wVersionRequested表示当前套接字库的版本号。
WORD wVersionRequested=MAKEWORD(2,0);
表示版本号为2.0
参数lpWSAData是指向结构体WSADATA的指针变量,表示获取到的套接字库的详细信息。
WSADATA结构体定义原型:
typedef struct WSAData{
WORD wVersion;//库文件建议用用程序使用套接字版本
WORD wHighVersion;//库文件支持的最高版本
char szDescription[WSADESCRIPTION_LEN+1];//描述库文件的字符串
char szSystemStatus[WSASYS_STATUS_LEN+1];//系统状态字符串
unsigned short iMaxSockets;//同时支持的最大套接字数
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
}
初始化套接字库代码:
WSAData data;//定义WSAData变量 WOED wVersionRequested=MAKEWORD(2,0);//定义套接字库版本号 ::WSAStartup(wVersionRequested,&data);//初始化套接字库
2、创建套接字句柄
调用函数socket(),函数原型:
SOCKET socket(int af,int type,int protocol);
参数af指定套接字所使用的地址格式
参数type指定套接字类型
SOCK_STREAM 创建流式套接字(基于TCP)
SOCK_DGRAM 创建数据报套接字(基于UDP)
SOCK_RAW 创建原始套接字
参数protocol:如果参数type已经指定套接字类型为TCP或UDP,则该参数可以置为0.
创建套接字句柄代码:
SOCKET s;//定义套接字句柄 s=::socket(AF_INET,SOCK_STREAM,0);//创建并返回套接字句柄
3、地址结构设置及字节顺序转换
此时我们必须了解两个概念:寻址方式和字节顺序。
寻址方式:套接字在各种协议中使用,所以为了区分网络协议,需设定寻址方式。TCP/IP地址中使用IP地址和端口号确定通信双方。
套接字地址结构定义:
struct sockaddr_in{
short sin_family;//指定地址家族(设置为AF_INET表示应用使用的是TCP/IP)
unsigned short sin_port;//指定端口号
struct in_addr sin_addr;//IP地址
char sin_zero[8];//留做备用,需要指定为0
};
sin_addr表示32位的IP地址结构,定义如下:
struct in_addr{
union{
struct{
unsigned char s_b1,s_b2,s_b3,s_b4;
}S_un_b;//用4个u_char字符描述IP地址
struct{
unsigned short s_w1,s_w2;
}S_un_w;//用两个u_short类型描述IP地址
unsigned long S_addr;//用一个u_long类型描述IP地址
}S_un;
};
通常我们使用1个u_long类型字符描述IP地址。
sockaddr_in addr;
addr.sin_addr.S_un.S_addr=inet_addr(“210.6.132.5”);
字节顺序
在Socket编程中,传输数据的排列顺序以网络字节顺序和主机字节顺序为主。主机向网络发送数据,需要把主机字节数据转化为网络字节顺序;主机接收网络发来的数据时,需要把网络字节顺序转化为主机字节顺序。从数据存储角度来看,网络字节顺序先存储最重要的字节,而主机字节顺序先存储不重要的字节。
在进行字节顺序转换时,会用到字节顺序转换函数
u_short htons(u_short hostshort);//将一个u_short类型IP地址从主机字节顺序转换为网络字节顺序
u_long htonl(u_long hostlong);//将一个u_long类型IP地址从主机字节顺序转换为网络字节顺序
u_long ntohl(u_long netlong);//将一个u_long类型IP地址从网络字节顺序转换为主机字节顺序
u_short ntohs(u_short netshort);//将一个u_short类型IP地址从网络字节顺序转换为主机字节顺序
unsigned long inet_addr(const char FAR*cp);//将一个字符串IP转换成以网络字节顺序排列的IP
char FAR*inet_ntoa(struct in_addr in);//讲一个以网络字节顺序排列的IP地址转换成一个字符串IP
地址结构设置及字节顺序转换代码:
sockaddr_in addr;//定义套接字地址结构变量 in_addr in_add;//定义IP地址结构变量 addr.sin_fimily=AF_INET;//指定地址家族为TCP/IP addr.sin_port=htons(80);//指定端口号 addr.sin_addr.S_un.S_addr=inet_addr('127.0.0.1');//将字符串IP转换为网络字节顺序排列的IP char address[]=inet_ntoa(addr.sin_addr.S_un.S_addr)//将网络字节顺序排列的IP转换为字符串IP
4、绑定地址信息
调用bind()函数,其函数原型:
int bind(SOCKET s,const struct sockaddr FAR* name,int namelen);
函数调用成功则返回0。
绑定地址信息代码:
::bind(s,(sockaddr)&addr,sizeof(addr));
5、监听套接字(仅用于流式套接字)
调用listen()函数,其原型为:
int listen(SOCKET s,int backlog);
参数backlog指定监听的最大连接数。
监听套接字代码:
::listen(s,5);//在套接字上监听,并且指定最大连接数为5.
6、接收客户端连接请求
客户端调用connect()函数发送连接请求,服务器调用accept()接收该请求。accept()函数原型:
SOCKET accept(SOCKET s,struct sockaddr FAR* addr,int FAR* addrlen);
接收客户端连接请求代码:
s1=::accept(s,(sockaddr*)&addr,&n);//接受连接请求
7、数据收发
调用send()函数和recv()函数,原型:
int send(SOCKET s,const char FAR *buf,int len,int flags);
int recv(SOCKET s,char FAR *buf,int len,int flags)
参数buf是指向数据缓冲区的指针变量,参数flags通常设置为0.
数据收发代码:
::send(s1,sztext,sizeof(sztext),0); ::recv(s,sztext,sizeof(sztext),0);
8、关闭套接字。
关闭套接字代码
::closesocket(s);
9、释放套接字库
释放套接字库
::WSACleanup();
完整源码:
/*Server.cpp*/ #include <winsock2.h>//包含头文件 #include <stdio.h> #include <windows.h> #pragma comment(lib,"WS2_32.lib")//显式连接套接字库 int main(){ //初始化套接字库 WSADATA data;//WSADATA结构体对象 WORD w=MAKEWORD(2,0);//定义版本号 ::WSAStartup(w,&data);//初始化套接字库 char sztext[]="欢迎你\r\n";//定义并初始化发送到客户端的字符数组 //创建套接字句柄 SOCKET s,s1;//定义连接套接字和数据收发套接字句柄 s=::socket(AF_INET,SOCK_STREAM,0);//创建TCP套接字 //地址结构设置及字节转换 sockaddr_in addr,addr2;//定义套接字地址结构 int n=sizeof(addr2);//获取套接字地址结构大小 addr.sin_family=AF_INET;//初始化地址结构 addr.sin_port=htons(75);//设置端口号 addr.sin_addr.S_un.S_addr=INADDR_ANY; //绑定套接字 ::bind(s,(sockaddr*)&addr,sizeof(addr)); //监听套接字 ::listen(s,5); printf("服务器已经启动\r\n");//输出提示信息 while(true){ //接受连接请求 s1=::accept(s,(sockaddr*)&addr2,&n); if(s1!=NULL){ printf("%s已经连接上\r\n",inet_ntoa(addr2.sin_addr)); //向客户端发送字符数组 ::send(s1,sztext,sizeof(sztext),0); } //关闭套接字句柄 ::closesocket(s); ::closesocket(s1); //释放套接字库 ::WSACleanup(); if(getchar()){ return 0; }else{ ::Sleep(100);//应用休眠0.1秒 } } }
相关文章推荐
- 一起talk C栗子吧(第一回:C语言实例概述)
- 用C++解越南小学三年级数学题
- 那些n位数
- 黑马程序员——C语言中的指针变量初步认识
- C/C++连接MYSQL
- C++基础学习(03AM)
- C++11 新特性整理
- 对学弟学妹学习C++的建议
- c++ ANSI、UNICODE、UTF8互转
- C/C++符号优先级和左/右结合性
- C/C++符号优先级和左/右结合性
- 【C语言】整人小程序
- VS2010 C++ MFC框架学习笔记3 - 控件Tab顺序设置及模态对话框
- C++ TinyXml操作
- 给定两个整数,比较出其中大者
- c++基础学习(02PM)
- C语言的数组初始化
- C语言fopen用法
- C++ 的 RTTI
- 标准C++中的string类的用法总结