参考文献:杨传栋, 张焕远. 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;
}