Server
#include<Winsock2.h>
#include<stdio.h>
#include <iostream>
#include <string>
using namespace std;
int main()
{
//**********************************************************
//第一步:加载socket库函数
//**********************************************************
//定义一个WORD的变量
WORD wVersionRequested;
WSADATA wsaData;
int err;
//低字节主版本号 高字节副版本号 如下是版本2.1
//(WORD)(1<<8|2)
wVersionRequested = MAKEWORD(2,1);
//WSAStartup应该与WSACleanup成对使用,WSAStartup的功能是初始化Winsock DLL,
//WSACleanup是来解除与Socket库的绑定并且释放Socket库所占用的系统资源
//WSAStartup函数的第一个参数是加载WinSock库的版本,WSAStartup函数的第二个参数中设置使用的WinSock库的版本,
//当正确初始化时,WSAStartup会返回0。但我在WSAStartup函数的第一个参数中胡乱设置了一个版本号,WSAStartup仍然会返回0。
//最后经测试发现,如果在WSAStartup函数第一个参数中设置的版本号不存在,那么会自动使用WinSock库中最高版本2.2
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
cout << "*******Fail to load Socket!*******" << endl;
return 0;
}
else
{
cout << "*******Success to load Socket!*******" << endl;
}
if (LOBYTE(wsaData.wVersion) != 2 ||HIBYTE(wsaData.wVersion) != 1)
{
cout << "*******版本不是2.1版本*******" << endl;
WSACleanup();
return 0;
}
//**********************************************************
//第二步创建套接字
//**********************************************************
//af: 一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。
//type: 指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。
// 常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
//protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,它们分别对应TCP传输协
// 议、UDP传输协议、STCP传输协议、TIPC传输协议。
SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
//**********************************************************
//第三步:绑定套接字
//**********************************************************
//获取地址结构
SOCKADDR_IN addrSrv;
//typedef struct sockaddr_in {
//#if(_WIN32_WINNT < 0x0600)
// short sin_family;
//#else //(_WIN32_WINNT < 0x0600)
// ADDRESS_FAMILY sin_family;
//#endif //(_WIN32_WINNT < 0x0600)
// USHORT sin_port;
// IN_ADDR sin_addr;
// CHAR sin_zero[8];
//} SOCKADDR_IN, *PSOCKADDR_IN;
//sa_family是地址家族,一般都是“AF_xxx”的形式。通常大多用的是都是AF_INET, 代表TCP / IP协议族。
//sa_data是14字节协议地址。
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
//将IP地址指定为INADDR_ANY,允许套接字向任何分配给本地机器的IP地址发送或接收数据
//监听所有发送请求的地址
//htonl()将主机的无符号长整形数转换成网络字节顺序。
//host to network, l 的意思是返回类型是long
addrSrv.sin_family = AF_INET;
//sin_family 表示地址族,对于IP地址,sin_family成员将一直是AF_INET
addrSrv.sin_port = htons(6000);
//htons()就是将一个数的高低位互换 高八位与低八位呼唤位置
//htons()将主机的无符号短整形数转换成网络字节顺序
bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
//int bind(int sockfd, const struct sockaddr * my_addr, socklen_t addrlen);
//返回:成功返回0,失败返回 - 1.
//参数列表中,sockfd 表示已经建立的socket编号(描述符);
//my_addr 是一个指向sockaddr结构体类型的指针;
//参数addrlen表示my_addr结构的长度,可以用sizeof函数获得。
listen(sockSrv, 5);
//参数一:用于标识一个已捆绑未连接套接口的描述字
//参数二:等待连接队列的最大长度
//监听客户端
//定义从客户端接受的地址信息
SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR);
cout << "**********等待客户端的连接**********" << endl;
SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);
//参数一:套接字描述符,该套接口在listen()后监听连接
//指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。
//addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数
//(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。
//addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数
while (1)
{
string sendBuf;
//sendBuf= "欢迎IP:"+inet_ntoa(addrClient.sin_addr) ;
//sprintf(sendBuf, "welcome %s to 济南", inet_ntoa(addrClient.sin_addr));
cout << "来自服务器的信息:";
cin >> sendBuf;
send(sockConn, sendBuf.c_str(), strlen(sendBuf.c_str()) + 1, 0);
char recvBuf[256];
recv(sockConn, recvBuf, 256, 0);
cout << "来自客户端的信息:" << recvBuf << endl;;
}
closesocket(sockConn);
WSACleanup();
return 0;
}
Client
#include<Winsock2.h>
#include <iostream>
#include <string>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
return 0;
}
if (LOBYTE(wsaData.wVersion) != 1 ||
HIBYTE(wsaData.wVersion) != 1) {
WSACleanup();
return 0;
}
//**********************************************************
//第一步,创建套接字
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
//定义套接字地址
SOCKADDR_IN addrSrv;
//获取服务器IP地址,inet_addr()将IP地址转为点分十进制的格式
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
//sin_family 表示地址族,对于IP地址,sin_family成员将一直是AF_INET
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
if (connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)) != 0)
{
cout << "与服务器连接失败" << endl;;
return 0;
}
else
{
cout << "**********连接服务器成功**********" << endl;
while (1)
{
string sendBuf;
cout << "来自客户端的信息:";
cin >> sendBuf;
send(sockClient, sendBuf.c_str(), strlen(sendBuf.c_str()) + 1, 0);
char recvBuf[256];
recv(sockClient, recvBuf, 256, 0);
cout << "来自服务器的信息:" << recvBuf << endl;
}
}
//关闭套接字
closesocket(sockClient);
//清除套接字资源
WSACleanup();
return 0;
}