参考文献:杨传栋, 张焕远. Windows网络编程基础教程[M]. 清华大学出版社, 2015.P114
服务器端程序代码:
//stdafx.h // stdafx.h : 标准系统包含文件的包含文件, // 或是经常使用但不常更改的 // 特定于项目的包含文件 // #pragma once #include "targetver.h" #include <stdio.h> #include <tchar.h> // TODO: 在此处引用程序需要的其他头文件
//targetver.h #pragma once // 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。 // 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 // WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 #include <SDKDDKVer.h>
//stdafx.cpp // stdafx.cpp : 只包括标准包含文件的源文件 // server.pch 将作为预编译头 // stdafx.obj 将包含预编译类型信息 #include "stdafx.h" // TODO: 在 STDAFX.H 中 // 引用任何所需的附加头文件,而不是在此文件中引用
server.cpp:
// server.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "iostream" #include "winsock2.h" #define PORT 65432 //定义端口号常量 端口号范围是0~65535 #pragma comment(lib, "ws2_32.lib") using namespace std; int main(int argc, char **argv) { /***定义相关的变量***/ SOCKET sock_server,newsock; //定义保存监听套接字及已连接套接字的变量 struct sockaddr_in addr; //用于填写绑定地址的结构变量 struct sockaddr_in client_addr;//存放客户端地址的sockaddr_in结构变量 char msgbuffer[256];//定义用于接收客户端发来信息的缓区 char msg[] ="Connect succeed.this message comes from server! \n"; //发给客户端的信息 /***初始化winsock2.DLL***/ WSADATA wsaData; WORD wVersionRequested=MAKEWORD(2,2); //生成版本号2.2 if(WSAStartup(wVersionRequested,&wsaData)!=0) { cout<<"加载winsock.dll失败!\n"; return 0; } /***创建套接字***/ if ((sock_server = socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR) { cout<<"创建套接字失败!错误代码:"<<WSAGetLastError()<<endl; WSACleanup(); return 0; } /***填写要绑定的本地地址***/ int addr_len = sizeof(struct sockaddr_in); memset((void *)&addr,0,addr_len); //将地址结构变量清0 addr.sin_family =AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY);//允许使用本机的任何IP地址 /***给监听套接字绑定地址***/ if(bind(sock_server,( struct sockaddr *)&addr,sizeof(addr))!=0) { cout<<"地址绑定失败!错误代码:"<<WSAGetLastError()<<endl; closesocket(sock_server); WSACleanup(); return 0; } /***将套接字设为监听状态****/ if(listen(sock_server,0)!=0) { cout<<"listen函数调用失败!错误代码:"<<WSAGetLastError()<<endl; closesocket(sock_server); WSACleanup(); return 0; } else cout<<"listenning......\n"; /***循环:接收连接请求并收发数据***/ int size; while(true) { if((newsock = accept (sock_server, (struct sockaddr *)&client_addr, &addr_len)) ==INVALID_SOCKET) { cout<<"accept函数调用失败!错误代码:"<<WSAGetLastError()<<endl; break; //终止循环 } else cout<<"成功接收一个连接请求!\n"; /***成功接收一个连接后先发送信息,再接收信息***/ size=send(newsock,msg,sizeof(msg),0);//给客户端发送一段信息 if(size== SOCKET_ERROR) { cout<<"发送信息失败!错误代码:"<<WSAGetLastError()<<endl; closesocket(newsock);//关闭已连接套接字 continue; //继续接收其他连接请求 } else if(size==0) { cout<<"对方已关闭连接!\n"; closesocket(newsock);//关闭已连接套接字 continue; //继续接收其他连接请求 } else cout<<"信息发送成功!\n"; if((size=recv(newsock,msgbuffer,sizeof(msgbuffer),0))<0)//接收信息 { cout<<"接收信息失败!错误代码:"<<WSAGetLastError()<<endl; closesocket(newsock);//关闭已连接套接字 continue; //继续接收其他连接请求 } else if(size==0) { cout<<"对方已关闭连接!\n"; closesocket(newsock);//关闭已连接套接字 continue; //继续接收其他连接请求 } else cout<<"收到的信息为:"<<msgbuffer<<"共size个字节"<<size<<endl; closesocket(newsock); //通信完毕关闭“已连接套接字” } /***结束处理***/ closesocket(sock_server);//关闭监听套接字 WSACleanup();//注销WinSock动态链接库 return 0; }
客户端代码:
stdafx.h
// stdafx.h : 标准系统包含文件的包含文件, // 或是经常使用但不常更改的 // 特定于项目的包含文件 // #pragma once #include "targetver.h" #include <stdio.h> #include <tchar.h> // TODO: 在此处引用程序需要的其他头文件
targetver.h
#pragma once // 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。 // 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 // WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 #include <SDKDDKVer.h>
stdafx.cpp
// stdafx.cpp : 只包括标准包含文件的源文件 // client.pch 将作为预编译头 // stdafx.obj 将包含预编译类型信息 #include "stdafx.h" // TODO: 在 STDAFX.H 中 // 引用任何所需的附加头文件,而不是在此文件中引用
client.cpp
// client.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "iostream" #include "winsock2.h" #define PORT 65432 //定义要访问的服务器端口常量 #pragma comment(lib, "ws2_32.lib") using namespace std; int main(int argc, char **argv) { //struct in_addr inad1; //struct sockaddr_in sd1; //struct sockaddr sad2; //cout << "sizeof(in_addr)=" << sizeof(in_addr) << endl; //cout << "sizeof(sockaddr_in)=" << sizeof(sockaddr_in) << endl; //cout << "sizeof(sockaddr)=" << sizeof(sockaddr) << endl; /***定义相关的变量***/ int sock_client; //定义客户端套接字 struct sockaddr_in server_addr; //定义存放服务器端地址的结构变量 int addr_len = sizeof(struct sockaddr_in); //地址结构变量的内存字节大小 char msgbuffer[1000]; //接收/发送信息的缓冲区 /***初始化winsock DLL***/ WSADATA wsaData; WORD wVersionRequested=MAKEWORD(2,2); //生成版本号2.2 if(WSAStartup(wVersionRequested,&wsaData)!=0) { cout<<"加载winsock.dll失败!\n"; return 0; } /***创建套接字***/ if ((sock_client = socket(AF_INET,SOCK_STREAM,0))<0) { cout<<"创建套接字失败!错误代码:"<<WSAGetLastError()<<endl; WSACleanup(); return 0; } /***填写服务器地址***/ char IP[20]="127.0.0.1"; //cout<<"请输入服务器IP地址:";//使用内网地址:192.168.2.116 或环回地址127.0.0.1 //cin>>IP; memset((void *)&server_addr,0,addr_len);//地址结构清0,初始化为0 //void * __cdecl memset(_Out_writes_bytes_all_(_Size) void * _Dst, _In_ int _Val, _In_ size_t _Size); //memset(void *s,int ch,size_t n);//将s所指向的某一块内存中的后n个 字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为s。 server_addr.sin_family =AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = inet_addr(IP);//填写服务器IP地址 /*inet_addr:地址转换函数, WINSOCK_API_LINKAGE unsigned long WSAAPI inet_addr( _In_z_ const char FAR * cp ); 将cp所指的点分十进制字符串表示的IP地址转换为32位无符号长整型,网络字节顺序。 */ /***与服务器建立连接***/ if(connect(sock_client,(struct sockaddr *)&server_addr,addr_len)!=0) { cout<<"连接失败!错误代码:"<<WSAGetLastError()<<endl; closesocket(sock_client); WSACleanup(); return 0; } ////获取与套接字关联的地址 //int namelen; //struct sockaddr_in client_addr; //int n = getsockname(sock_client, (struct sockaddr*)&client_addr, &namelen); //if (n == SOCKET_ERROR) //{ // cout << "getsockname error!" << endl; //} //else //{ // cout << "本地套接字端口号:" << client_addr.sin_port << ",IP地址是:" << inet_ntoa(client_addr.sin_addr) << endl; //} /***接收信息并显示***/ int size; if((size=recv(sock_client,msgbuffer,sizeof(msgbuffer),0))<0) { cout<<"接收信息失败!错误代码:"<<WSAGetLastError()<<endl; closesocket(sock_client);//关闭已连接套接字 WSACleanup(); //注销WinSock动态链接库 return 0; } else if (size == 0) { cout << "对方已关闭连接!\n"; closesocket(sock_client);//关闭已连接套接字 WSACleanup(); //注销WinSock动态链接库 return 0; } else cout << "接受到的字节数:size=" << size << endl; cout<<"The message from Server: "<<msgbuffer<<endl; /***从键盘输入一行文字发送给服务器***/ cout<<"从键盘输入发给服务器的信息!\n"; cin>>msgbuffer; cout << "sizeof(msgbuffer)=" << sizeof(msgbuffer) << endl;//sizeof(msgbuffer)=1000 if((size=send(sock_client,msgbuffer,sizeof(msgbuffer),0))<0) cout<<"发送信息失败!错误代码:"<<WSAGetLastError()<<endl; else if(size==0) cout<<"对方已关闭连接!\n"; else cout<<"信息发送成功!\n"; /***结束处理***/ closesocket(sock_client); //关闭socket WSACleanup(); //注销WinSock动态链接库 ////获取与套接字关联的地址 //int namelen; //struct sockaddr_in client_addr; //int n = getsockname(sock_client, (struct sockaddr*)&client_addr, &namelen); //if (n == SOCKET_ERROR) //{ // cout << "getsockname error!" << endl; //} //else //{ // cout << "本地套接字端口号:" << client_addr.sin_port << ",IP地址是:" << inet_ntoa(client_addr.sin_addr) << endl; //} ///* //#if INCL_WINSOCK_API_PROTOTYPES //_WINSOCK_DEPRECATED_BY("inet_ntop() or InetNtop()") //WINSOCK_API_LINKAGE //char FAR * //WSAAPI //inet_ntoa( //_In_ struct in_addr in //); //#endif // INCL_WINSOCK_API_PROTOTYPES //chat* inet_ntoa(struct in_addr in); //in:是一个保存有32位IP地址的二进制IP地址的in_addr结构变量 //函数功能:将一个保存在in_addr结构变量中的长整型IP地址转换为点分十进制字符串形式。 //*/ //int serverNameLen; //struct sockaddr_in server_addr2; //int servern = getpeername(sock_client, (struct sockaddr*)&client_addr, &serverNameLen); //if (servern == SOCKET_ERROR) //{ // cout << "getsockname error!" << endl; //} //else //{ // cout << "本地套接字端口号:" << server_addr2.sin_port << ",IP地址是:" << inet_ntoa(server_addr2.sin_addr) << endl; //} system("pause"); return 0; }