WinSock网络通信
来源:互联网 发布:科幻小说 知乎 编辑:程序博客网 时间:2024/05/18 03:43
前言:
Winsock是Windows下的网络编程接口,它是由Unix下的BSD Socket发展而来,是一个与网络协议无关的编程接口。
构建编程环境
Winsock在常见的Windows平台上有两个主要的版本,即Winsock1和Winsock2。编写与Winsock1兼容的程序你需要引用头文件WINSOCK.H,如果编写使用Winsock2的程序,则需要引用WINSOCK2.H。此外还有一个MSWSOCK.H头文件,它是专门用来支持在Windows平台上高性能网络程序扩展功能的。使用WINSOCK.H头文件时,同时需要库文件WSOCK32.LIB,使用WINSOCK2.H时,则需要WS2_32.LIB,如果使用MSWSOCK.H中的扩展API,则需要MSWSOCK.LIB。正确引用了头文件,并链接了对应的库文件,你就构建起编写WINSOCK网络程序的环境了。
初始化Winsock
每个Winsock程序必须使用WSAStartup载入合适的Winsock动态链接库,如果载入失败,WSAStartup将返回SOCKET_ERROR
主要代码分析
服务端程序:
第一步:包含WinSocket的头文件和动态链接库(DLL)
#include <Winsock2.h>#include <windows.h>#pragma comment(lib,"ws2_32")
第二步:初始化WSAStartup
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出错!"<<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<<"套接字打开错误"<<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地址进行连接int duankou;cout << "请输入端口号:" ;cin >> duankou;ServerAddr.sin_port=htons(duankou);//侦听端口为duankou,这里使用了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 << "连接失败" << endl; } else{ cout << "连接到地址:" << inet_ntoa(Clientaddr.sin_addr) << endl; }
第七步:如果accept成功,recv消息
由于要多次交互,所以这是在一个while循环中实现
在MSDN中recv原型如下:
int recv( __in SOCKET s, __out char* buf, __in int len, __in int flags);
第一个参数为accept返回的socket,第二个参数为输出接收的消息的一个指针,第三个为消息的长度,第四个为标志,设定接收数据的方式,代码如下:
while (TRUE){ cout << "准备接受信息" << endl; char RecvMessage[1024]; int MessageLen = recv(ClientSocket, RecvMessage, sizeof(RecvMessage), 0); if (MessageLen < 0){ cout << "接受信息失败!" << endl; } else{ RecvMessage[MessageLen] = 0x00; if (strcmp(RecvMessage, "bye") == 0) { cout << "客户端已关闭,此次交流结束!" << endl; system("pause");//处理客户端关闭状态 cout << "服务器继续监听端口:" << duankou << endl; break; } cout << "接受成功,信息为:" << RecvMessage << endl; }
第八步:回复客户端消息 send
send在MSDN中的代码如下:
int send( __in SOCKET s, __in const char* buf, __in int len, __in int flags);
第一个参数为accept返回的socket,第二个参数为内容的开始地址,第三个为长度,第四个为发送的方式,代码如下:
cout << "准备发送信息" << endl; cout << "请输入信息:"; char Message[100]; cin >> Message; if (strcmp(Message, "bye") == 0) { send(ClientSocket, Message, strlen(Message), 0); flag = 1; break; } cout << "发送信息:" << Message << endl; if (send(ClientSocket, Message, strlen(Message), 0) < 0){ cout << "发送信息失败!" << endl; } else{ cout << "发送信息成功!" << endl; } }
第九步:完成后,关闭客户端与服务端的socket:
closesocket(ClientSocket); if (flag) break;
flag用于退出整个服务端。当flag为1时,退出。
第十步:“清理”现场:
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出错!" << endl; WSACleanup(); } SOCKET ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ServerSocket == INVALID_SOCKET){ cout << "套接字打开错误" << endl; } sockaddr_in ServerAddr; ServerAddr.sin_family = AF_INET; ServerAddr.sin_addr.S_un.S_addr = INADDR_ANY; int duankou; cout << "请输入端口号:" ; cin >> duankou; ServerAddr.sin_port = htons(duankou); 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); cout << "服务器初始化成功,正在监听" << endl; int flag = 0; while (TRUE){ ClientSocket = accept(ServerSocket, (LPSOCKADDR)&Clientaddr, &lAddrlen); if (ClientSocket == INVALID_SOCKET){ cout << "连接失败" << endl; } else{ cout << "连接到地址:" << inet_ntoa(Clientaddr.sin_addr) << endl; } while (TRUE){ cout << "准备接受信息" << endl; char RecvMessage[1024]; int MessageLen = recv(ClientSocket, RecvMessage, sizeof(RecvMessage), 0); if (MessageLen < 0){ cout << "接受信息失败!" << endl; } else{ RecvMessage[MessageLen] = 0x00; if (strcmp(RecvMessage, "bye") == 0) { cout << "客户端已关闭,此次交流结束!" << endl; system("pause"); cout << "服务器继续监听端口:" << duankou << endl; break; } cout << "接受成功,信息为:" << RecvMessage << endl; } cout << "准备发送信息" << endl; cout << "请输入信息:"; char Message[100]; cin >> Message; if (strcmp(Message, "bye") == 0) { send(ClientSocket, Message, strlen(Message), 0); flag = 1; break; } cout << "发送信息:" << Message << endl; if (send(ClientSocket, Message, strlen(Message), 0) < 0){ cout << "发送信息失败!" << endl; } else{ cout << "发送信息成功!" << endl; } } closesocket(ClientSocket); if (flag) break; } closesocket(ServerSocket); WSACleanup(); return 0;}
客户端程序:
第一步 包含头文件和DLL
#include <winsock.h>#include <iostream>#pragma comment(lib,"ws2_32")
第二步 初始化WSAStartup
WORDwVersion = MAKEWORD(2,2);WSADATA ClientData;if(WSAStartup(wVersion,&ClientData)){cout<<" WSAStartup打开失败l"<<endl;}
第三步 打开套接字
SOCKET ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (ClientSocket == INVALID_SOCKET){ cout << "套接字打开失败" << endl;}
第四步 connect 连接服务器
int duankou; cout << "请输入端口号:"; cin >> duankou; Clientaddr.sin_port = htons(duankou); Clientaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//inet_addr(),参数为一个字符串,将IP字符串的值传递给inet_addr Clientaddr.sin_family = AF_INET; if (connect(ClientSocket, (LPSOCKADDR)&Clientaddr, sizeof(Clientaddr))){ cout << "连接失败!" << endl; closesocket(ClientSocket); WSACleanup(); return 0; } cout << "客户端初始化成功,准备交流" << endl;
第五步 信息交互
while (1) { cout << "请输入信息:"; char buff[1000]; cin >> buff; if (strcmp(buff, "bye") == 0) { send(ClientSocket, buff, strlen(buff), 0); break; } cout << "发送信息:" << buff << endl; if (send(ClientSocket, buff, strlen(buff), 0) < 0){ cout << "发送失败!" << endl; } else{ cout << "发送成功!" << endl; } cout << "准备接受信息" << endl; char RecMessage[1024]; int MessageLen = recv(ClientSocket, RecMessage, sizeof(RecMessage), 0); //cout << MessageLen << endl;测试用 if (MessageLen < 0){ cout << "接受失败" << endl; } else{ RecMessage[MessageLen] = 0X00; if (strcmp(RecMessage, "bye") == 0)//处理bye过程 { cout << "服务器已关闭,交流结束" << endl; system("pause"); break; } cout << "接受成功,信息为:" << RecMessage << endl; } }
第七步 释放资源
closesocket(ClientSocket);WSACleanup();
整体代码:
#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打开失败" << endl; } SOCKET ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ClientSocket == INVALID_SOCKET){ cout << "套接字打开失败" << endl; } sockaddr_in Clientaddr; int duankou; cout << "请输入端口号:"; cin >> duankou; Clientaddr.sin_port = htons(duankou); Clientaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//inet_addr(),参数为一个字符串,将IP字符串的值传递给inet_addr Clientaddr.sin_family = AF_INET; if (connect(ClientSocket, (LPSOCKADDR)&Clientaddr, sizeof(Clientaddr))){ cout << "连接失败!" << endl; closesocket(ClientSocket); WSACleanup(); return 0; } cout << "客户端初始化成功,准备交流" << endl; while (1) { cout << "请输入信息:"; char buff[1000]; cin >> buff; if (strcmp(buff, "bye") == 0) { send(ClientSocket, buff, strlen(buff), 0); break; } cout << "发送信息:" << buff << endl; if (send(ClientSocket, buff, strlen(buff), 0) < 0){ cout << "发送失败!" << endl; } else{ cout << "发送成功!" << endl; } cout << "准备接受信息" << endl; char RecMessage[1024]; int MessageLen = recv(ClientSocket, RecMessage, sizeof(RecMessage), 0); //cout << MessageLen << endl;测试用 if (MessageLen < 0){ cout << "接受失败" << endl; } else{ RecMessage[MessageLen] = 0X00; if (strcmp(RecMessage, "bye") == 0) { cout << "服务器已关闭,交流结束" << endl; system("pause"); break; } cout << "接受成功,信息为:" << RecMessage << endl; } } closesocket(ClientSocket); WSACleanup(); return 0;}
- Winsock网络通信
- Winsock网络通信
- Winsock网络通信
- Winsock网络通信
- Winsock网络通信
- Winsock网络通信
- Winsock网络通信
- Winsock网络通信
- Winsock网络通信
- Winsock网络通信过程
- WinSock网络通信
- WinSock网络通信程序设计入门
- WinSock网络通信程序设计入门
- Winsock控件,实现网络点对点通信
- TCP/IP网络通信 WinSock编程
- Winsock开发网络通信程序的经典入门
- Winsock开发网络通信程序的经典入门
- Winsock开发网络通信程序的经典入门
- 数据库查询记录中某些字段重复的方法
- iOS App热修复的设计方案及简单实践
- Oracle客户端登陆界面database扫描问题
- JAVA中int、String的类型转换
- Java 生成二维码
- WinSock网络通信
- Oracle UTL_RAW
- 内置晶体RTC的优势分析
- Spring MVC Controller配置方式
- 设计模式 - 结构型模式 - 装饰模式
- Oracle系统权限的分类
- 将{"result": [ { "Name1":"data1" , "Name2":"data2" }]}转成添加到map集合
- windows 10 及 windows server 2012 中vnc不显示鼠标光标的问题解决
- java利器jodd打印输出http协议信息