Winsocket编程一般步骤-服务端编程

来源:互联网 发布:windows系统是什么 编辑:程序博客网 时间:2024/05/21 10:30

Socket编程是网络编程的重要组成部分,编写简单的服务端程的程序的一般的步骤如下

第一步:包含WinSocket的头文件和动态链接库(DLL)

#include <Winsock2.h>#include <windows.h>#pragma comment(lib,"ws2_32")

第二步:初始化WSAStartup 在MSDN中WSAStarup的原型如下:

int WSAStartup(  __in   WORD wVersionRequested,  __out  LPWSADATA lpWSAData);


其中的第一个参数是版本,第二个参数是一个指向WSADATA结构体的指针,代码如下:

WORD Version = MAKEWORD(2,2);  //通过MAKEWORD来设定版本,高版本和低版本都为2,也就是限定了版本必须为2WSADATA wsadata ;                       //结构体的一个成员 wsadata//初始化并判断是不是成功,如果成功的话返回的是0,不成功的话返回的值为非0,那么就要使用WSAleanup()函数了if(WSAStartup(Version,&wsadata)){cout<<"WSAStartup Error!"<<endl;WSACleanup();}

第三部,初始化一个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_UDPSOCKET ServerSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(ServerSocket ==INVALID_SOCKET){cout<<"Socket Fail"<<endl;}

第四步: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_INETServerAddr.sin_addr.S_un.S_addr=INADDR_ANY;//允许任意的IP地址进行连接ServerAddr.sin_port=htons(2012);//侦听端口为2012,这里使用了htons函数//这里需要说明的是需要对第二个参数进行强制类型转换,(LPSOCKADDR)&ServerAddr,并且判断是不是bind成功,成功后返回的是为0if(bind(ServerSocket,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr))){cout<<"bind Fail"<<endl;}

第五步:侦听
在MSDN中listen的原型如下:

int listen(  __in  SOCKET s,  __in  int backlog);

依然第一个参数为初始化了的socket,第二个参数为最大允许的连接数,代码如下:

//这里依然使用的是上面的socket:ServerSocketif(listen(ServerSocket,5)){cout<<"listen Fail"<<endl;}

第六步: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);//与上面类似,需要强制转换,第一个参数为已经初始化的socketif(ClientSocket==INVALID_SOCKET){cout<<"accept Fail"<<endl;}else{cout<<"接受到一个信息"<<endl;}

第七步:如果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"<<endl;}

第八步:(可选):回复客户端消息 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"<<endl;}

第九步:完成后,关闭客户端与服务端的socket:

closesocket(ClientSocket);}//上面while的结束部分

第十步:“清理”现场:

closesocket(ServerSocket);WSACleanup();return 0;

总结下,代码如下:

#include <iostream>#include <Winsock.h>#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!"<<endl;WSACleanup();}SOCKET ServerSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(ServerSocket ==INVALID_SOCKET){cout<<"Socket Fail"<<endl;}sockaddr_in ServerAddr;ServerAddr.sin_family=AF_INET;ServerAddr.sin_addr.S_un.S_addr=INADDR_ANY;ServerAddr.sin_port=htons(2012);if(bind(ServerSocket,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr))){cout<<"bind Fail"<<endl;}if(listen(ServerSocket,5)){cout<<"listen Fail"<<endl;}sockaddr_in Clientaddr;SOCKET ClientSocket;int lAddrlen=sizeof(Clientaddr);while(TRUE){ClientSocket=accept(ServerSocket,(LPSOCKADDR)&Clientaddr,&lAddrlen);if(ClientSocket==INVALID_SOCKET){cout<<"accept Fail"<<endl;}else{cout<<"接受到一个信息"<<endl;}char RecvMessage[1024];if(recv(ClientSocket,RecvMessage,1024,0)<0){cout<<"recv Message Fail"<<endl;}char * Message ="HellO Client!";if(send(ClientSocket,Message,strlen(Message),0)<0){cout<<"send Message Fail"<<endl;}closesocket(ClientSocket);}closesocket(ServerSocket);WSACleanup();return 0;}
转自:http://kuaile.in/archives/311

Winsocket编程一般步骤-客户端编程

前面的文章有详细的介绍过服务端的编程,在客户端的代码的实现相对于服务端的代码要简单些,客户端可以通过IP地址直接连接,也可以通过静态域名或者是3322动态域名来连接服务器,下面是具体的代码的实现

第一步 包含头文件和DLL

?
1
2
3
#include <winsock.h>
#include <iostream>
#pragma comment(lib,"ws2_32")

第二步 初始化WSAStartup

?
1
2
3
4
5
WORD wVersion = MAKEWORD(2,2);
WSADATA ClientData;
if(WSAStartup(wVersion,&ClientData)){
cout<<"WSAStartup Fail"<<endl;
}


第三步 (可选):针对于使用静态域名或者是3322等动态域名进行连接,需要对域名进行DNS解析获得对应的IP地址,如果使用的是ip地址进行连接的话,直接跳到第四步

?
1
2
3
4
5
6
7
8
9
//通过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 连接服务器

?
1
2
3
4
5
6
7
8
9
10
11
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"<<endl;
        //如果连接失败,释放资源
    closesocket(ClientSocket);
    WSACleanup();
    return 0;
}

第五步 send 发送消息

?
1
2
3
4
5
6
7
char * buff = "Hello Server!";
if(send(ClientSocket,buff,strlen(buff),0)<0){
    cout<<"send Fail"<<endl;
}
else{
    cout<<"send Success"<<endl;
}

第六步 recv 接收消息

?
1
2
3
4
5
6
7
8
9
10
11
12
char  RecMessage[1024];
int MessageLen=recv(ClientSocket,RecMessage,1024,0);
if(MessageLen<0){
    cout<<"recv Fail"<<endl;
}
else{
 /*通过recv获取的长度为MessageLen,那么将数组的地MessageLen的值置为‘\0’,也就是给
 字符串数组加上一个结束符,那么cout遇到结束符就能停止输出了,免去了使用for循环,提高了
 程序的执行效率*/
RecMessage[MessageLen]=0x00;
cout<<RecMessge<<endl;
}

第七步 释放资源

?
1
2
closesocket(ClientSocket);
WSACleanup();
?
1
/*备注:如果想要实现连接上了服务器后与服务器进行不间断的交流的话,只需要将send和recv重写为两个函数,通过向函数传递socket来实现简单的交流的目的*/

完整的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <windows.h>
#include <Winsock.h>
#include <iostream>
#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"<<endl;
}
 
SOCKET ClientSocket  = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(ClientSocket==INVALID_SOCKET){
    cout<<"socket Fail"<<endl;
}
//通过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"<<endl;
    closesocket(ClientSocket);
    WSACleanup();
    return 0;
}
char * buff = "Hello Server!";
if(send(ClientSocket,buff,strlen(buff),0)<0){
    cout<<"send Fail"<<endl;
}
else{
    cout<<"send Success"<<endl;
}
 
char  RecMessage[1024];
int MessageLen=recv(ClientSocket,RecMessage,1024,0);
if(MessageLen<0){
    cout<<"recv Fail"<<endl;
}
else{
RecMessage[MessageLen]= 0X00;
cout<<RecMessage<<endl;
}
closesocket(ClientSocket);
WSACleanup();
 
    return 0;
}
                                             
0 0