Socket编程是网络编程的重要组成部分,编写简单的服务端程的程序的一般的步骤如下
第一步:包含WinSocket的头文件和动态链接库(DLL)
#include#include #pragma comment(lib,"ws2_32")
第二步:初始化WSAStartup 在MSDN中WSAStarup的原型如下:
int WSAStartup( __in WORD wVersionRequested, __out LPWSADATA lpWSAData );
其中的第一个参数是版本,第二个参数是一个指向WSADATA结构体的指针,代码如下:
WORD Version = MAKEWORD(2,2); //通过MAKEWORD来设定版本,高版本和低版本都为2,也就是限定了版本必须为2 WSADATA wsadata ; //结构体的一个成员 wsadata //初始化并判断是不是成功,如果成功的话返回的是0,不成功的话返回的值为非0,那么就要使用WSAleanup()函数了 if(WSAStartup(Version,&wsadata)){ cout<<"WSAStartup Error!"<第三部,初始化一个Socket,
在MSDN中socket的原型如下
SOCKET WSAAPI socket( __in int af, __in int type, __in int protocol );其中第一个参数为网络层协议类型,第二个参数为socket类型,第三个参数为传输层的协议类型,代码如下:
//第一个参数多数时候为AF_INET,第二个参数可以为SOCK_STREAM适用于可信连接,也就是tcp链接,或者为SOCK_DGRAM,适用于UDP协议 第三个参数为传输层协议,如果第二个参数为SOCK_STREAM,这里就为IPPROTO_TCP,如果是SOCK_DGRAM,这里就为IPPROTO_UDP SOCKET ServerSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(ServerSocket ==INVALID_SOCKET){ cout<<"Socket Fail"<第四步:bind
在MSDN中bind的定义如下:int bind( __in SOCKET s, __in const struct sockaddr* name, __in int namelen );第一个参数一个已经初始化的socket,第二个参数为执行sockaddr或者是sockaddr_in的结构体的起始地址,
第三个参数为结构体的大小,代码如下:
sockaddr_in ServerAddr;//定义一个结构体成员,这里使用的是sockaddr_in结构体 ServerAddr.sin_family=AF_INET;//初始化成员的sin_family为AF_INET ServerAddr.sin_addr.S_un.S_addr=INADDR_ANY;//允许任意的IP地址进行连接 ServerAddr.sin_port=htons(2012);//侦听端口为2012,这里使用了htons函数 //这里需要说明的是需要对第二个参数进行强制类型转换,(LPSOCKADDR)&ServerAddr,并且判断是不是bind成功,成功后返回的是为0 if(bind(ServerSocket,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr))){ cout<<"bind Fail"<第五步:侦听
在MSDN中listen的原型如下:int listen( __in SOCKET s, __in int backlog );依然第一个参数为初始化了的socket,第二个参数为最大允许的连接数,代码如下:
//这里依然使用的是上面的socket:ServerSocket if(listen(ServerSocket,5)){ cout<<"listen Fail"<第六步:accept
在MSDN中原型如下:SOCKET accept( __in SOCKET s, __out struct sockaddr* addr, __inout int* addrlen );第一个参数一个新的客户端的Socket,这里需要定义一个,第二个参数依然为执行sockaddr或者是sockaddr_in的结构体的首地址,第三个参数为长度,这里accept负责对新定义的socket进行初始化,如果成功accept返回的一个可用的sokcet。
代码如下:sockaddr_in Clientaddr;//定义一个结构体成员 SOCKET ClientSocket;//定义一个socket用于接收accept的返回值 int lAddrlen=sizeof(Clientaddr);//获取结构体的长度 while(TRUE){//因为要一直的侦听,所以这里使用无限循环 ClientSocket=accept(ServerSocket,(LPSOCKADDR)&Clientaddr,&lAddrlen); //与上面类似,需要强制转换,第一个参数为已经初始化的socket if(ClientSocket==INVALID_SOCKET){ cout<<"accept Fail"<接受到一个信息"< 第七步:如果accept成功,recv消息
在MSDN中recv原型如下:int recv( __in SOCKET s, __out char* buf, __in int len, __in int flags );第一个参数为accept返回的socket,第二个参数为输出接收的消息的一个指针,第三个为消息的长度,第四个为标志,设定接收数据的方式,代码如下:
char RecvMessage[1024]; //判断是不是成功接收,成功接收返回的是接收的数据的长度, if(recv(ClientSocket,RecvMessage,1024,0){ cout<<"recv Message Fail"<第八步:(可选):回复客户端消息 send
send在MSDN中的代码如下:int send( __in SOCKET s, __in const char* buf, __in int len, __in int flags );第一个参数为accept返回的socket,第二个参数为内容的开始地址,第三个为长度,第四个为发送的方式,代码如下:
char * Message ="HellO Client!"; //判断是不是成功发送,成功发送返回的是发送的字节数, if(send(ClientSocket,Message,strlen(Message),0){ cout<<"send Message Fail"<第九步:完成后,关闭客户端与服务端的socket:
closesocket(ClientSocket); }//上面while的结束部分
第十步:“清理”现场:
closesocket(ServerSocket); WSACleanup(); return 0;总结下,代码如下:
#include#include #pragma comment(lib,"ws2_32") using namespace std; int main(int argc,char argv[]) { WORD Version = MAKEWORD(2,2); WSADATA wsadata ; if(WSAStartup(Version,&wsadata)){ cout<<"WSAStartup Error!"< 转自:http://kuaile.in/archives/311Winsocket编程一般步骤-客户端编程
前面的文章有详细的介绍过服务端的编程,在客户端的代码的实现相对于服务端的代码要简单些,客户端可以通过IP地址直接连接,也可以通过静态域名或者是3322动态域名来连接服务器,下面是具体的代码的实现
第一步 包含头文件和DLL
123#include
#include
#pragma comment(lib,"ws2_32")
第二步 初始化WSAStartup
12345WORD
wVersion = MAKEWORD(2,2);
WSADATA ClientData;
if
(WSAStartup(wVersion,&ClientData)){
cout<<
"WSAStartup Fail"
<
}
第三步 (可选):针对于使用静态域名或者是3322等动态域名进行连接,需要对域名进行DNS解析获得对应的IP地址,如果使用的是ip地址进行连接的话,直接跳到第四步
123456789//通过gethostbyname来获取域名的数字IP地址,gethostbyname返回的是hostent结构体指针
hostent * RemoteAddr;
RemoteAddr=gethostbyname(
"kuaile.in"
);
/*通过inet_ntoa将数字地址转换为ascii形式,也就是类似于xxx.xxx.xxx.xxx形式
由于gethostbyname返回的数字地址保存在h_addr_list数组中,这里去第一个数字地址来转换 由MSDN可知,inet_ntoa的参数为 An in_addr structure that represents an Internet host address ,
那么需要强制转换地址为结构体指针的形式,然后取地址
inet_ntoa返回的是字符串数组,通过定义一个字符串指针来接受ASCII形式的IP地址的首地址*/
char
* IP;
IP=inet_ntoa(*(
struct
in_addr *)RemoteAddr->h_addr_list[0]);
第四步 connect 连接服务器
1234567891011sockaddr_in Clientaddr;
Clientaddr.sin_port = htons(2012);
Clientaddr.sin_addr.S_un.S_addr = inet_addr(IP);
//inet_addr(),参数为一个字符串,将IP字符串的地址传递给inet_addr
Clientaddr.sin_family =AF_INET;
if
(connect(ClientSocket,(LPSOCKADDR)&Clientaddr,
sizeof
(Clientaddr))){
cout<<
"connect Fail"
<
//如果连接失败,释放资源
closesocket(ClientSocket);
WSACleanup();
return
0;
}
第五步 send 发送消息
1234567char
* buff =
"Hello Server!"
;
if
(send(ClientSocket,buff,
strlen
(buff),0)<0){
cout<<
"send Fail"
<
}
else
{
cout<<
"send Success"
<
}
第六步 recv 接收消息
123456789101112char
RecMessage[1024];
int
MessageLen=recv(ClientSocket,RecMessage,1024,0);
if
(MessageLen<0){
cout<<
"recv Fail"
<
}
else
{
/*通过recv获取的长度为MessageLen,那么将数组的地MessageLen的值置为‘\0’,也就是给
字符串数组加上一个结束符,那么cout遇到结束符就能停止输出了,免去了使用for循环,提高了
程序的执行效率*/
RecMessage[MessageLen]=0x00;
cout<
}
第七步 释放资源
12closesocket(ClientSocket);
WSACleanup();
1/*备注:如果想要实现连接上了服务器后与服务器进行不间断的交流的话,只需要将send和recv重写为两个函数,通过向函数传递socket来实现简单的交流的目的*/
完整的代码如下:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#include
#include
#include
#pragma comment(lib,"ws2_32")
using
namespace
std;
int
main(
int
argc,
char
argv[])
{
WORD
wVersion = MAKEWORD(2,2);
WSADATA ClientData;
if
(WSAStartup(wVersion,&ClientData)){
cout<<
"WSAStartup Fail"
<
}
SOCKET ClientSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if
(ClientSocket==INVALID_SOCKET){
cout<<
"socket Fail"
<
}
//通过gethostbyname来获取域名的数字IP地址,gethostbyname返回的是hostent结构体指针
hostent * RemoteAddr;
RemoteAddr=gethostbyname(
"kuaile.in"
);
//通过inet_ntoa将数字地址转换为ascii形式,也就是类似于xxx.xxx.xxx.xxx形式
//由于gethostbyname返回的数字地址保存在h_addr_list数组中,这里去第一个数字地址来转换
//由MSDN可知,inet_ntoa的参数为 An in_addr structure that represents an Internet host address ,
//那么需要强制转换地址为结构体指针的形式,然后取地址
//inet_ntoa返回的是字符串数组,通过定义一个字符串来接受ASCII形式的IP地址
char
* IP;
IP=inet_ntoa(*(
struct
in_addr *)RemoteAddr->h_addr_list[0]);
sockaddr_in Clientaddr;
Clientaddr.sin_port = htons(2012);
Clientaddr.sin_addr.S_un.S_addr = inet_addr(IP);
//inet_addr(),参数为一个字符串,将IP字符串的值传递给inet_addr
Clientaddr.sin_family =AF_INET;
if
(connect(ClientSocket,(LPSOCKADDR)&Clientaddr,
sizeof
(Clientaddr))){
cout<<
"connect Fail"
<
closesocket(ClientSocket);
WSACleanup();
return
0;
}
char
* buff =
"Hello Server!"
;
if
(send(ClientSocket,buff,
strlen
(buff),0)<0){
cout<<
"send Fail"
<
}
else
{
cout<<
"send Success"
<
}
char
RecMessage[1024];
int
MessageLen=recv(ClientSocket,RecMessage,1024,0);
if
(MessageLen<0){
cout<<
"recv Fail"
<
}
else
{
RecMessage[MessageLen]= 0X00;
cout<
}
closesocket(ClientSocket);
WSACleanup();
return
0;
}