#include<WINSOCK2.H>
#include<stdio.h>
#include<iostream>
using namespace std;
#pragma comment(lib,"WS2_32.lib")
#define BUFFER_SIZE 1024 //缓冲区大小
#define _WINSOCK_DEPRECATED_NO_WARNINGS
//#define MAKEWORD(a,b) ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8)) //makeword是将两个byte型合并成一个word型,一个在高8位(b),一个在低8位(a)
int main(){
WSADATA WSAData;
SOCKET sClient; //用于和客户端socket进行通信
SOCKET sServer; //用于和本地地址绑定的socket
int err_code; //存储返回的错误代码
char buffer[BUFFER_SIZE]; //缓冲区
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0){ //WSAStartup执行成功后返回0。
printf("WSAStartup failed,错误代码:%d\n", WSAGetLastError());
return -1;
} //初始化winsock
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //创建监听的socket; AF_INET:IPv4 Internet协议;
//SOCK_STREAM:Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输
//IPPROTO_TCP:协议编号
if (sServer == INVALID_SOCKET){
printf("创建Socket失败,错误代码:%d\n", WSAGetLastError());
WSACleanup();//清除初始化的Winsock
return -1;
}
SOCKADDR_IN addrServ; //在监听的SOCKET绑定到本地之前,需要设置服务器Socket的地址
addrServ.sin_family = AF_INET;
//htons将无符号短整型主机字节序转换为网络字节序
addrServ.sin_port = htons(7003);//这里为什么不能用htonl()函数来转换呢,因为SOCKADDR_IN里面声明的端口号为u_shortk类型
addrServ.sin_addr.S_un.S_addr = htons(INADDR_ANY);//服务器监听端口为INADDR_ANY,即在任意本地地址(0.0.0.0)上进行监听
//bind函数用于将套接字与指定端口相连,sServer为调用socket函数后返回的文件描述符,addrServ指向sServer结构体的指针(该结构体中保存有端口和IP地址信息)
err_code = bind(sServer, (const sockaddr *)&addrServ, sizeof(SOCKADDR_IN)); //将用于绑定的sService绑定到本地地址
if (err_code == SOCKET_ERROR){
printf("bind failed,错误代码:%d\n", WSAGetLastError());
closesocket(sServer);
WSACleanup(); //终止对套接字库的使用
return -1;
}
err_code = listen(sServer, 1);
//监听客户端socket, 第一个参数为与本地地址绑定的socket, 第二个参数表示等待连接队列的最大长度
if (err_code == SOCKET_ERROR){
printf("listener failed,错误代码:%d\n", WSAGetLastError());
closesocket(sServer);
WSACleanup();
return -1;
}
std::cout << "TCP Server start...\n"<<endl ;
//与客户端连接
sockaddr_in addrClient;
int addrClientlen = sizeof(addrClient);
//TCP服务器依次调用socket(),bind(),listen()之后,就会监听指定的socket地址;
//TCP客户端在依次调用socket(),connect()之后就会向TCP服务器发送一个连接请求。
//TCP服务器在监听到这个请求之后,就会调用accept函数取接收请求,这样连接就建立好了。
//返回的是已连接的客户端socket描述符
//参数:
/* sockfd:服务器的socket描述符
addrClient:指向struct sockaddr的指针,用于返回客户端的协议地址
addrClientlen:返回协议地址的长度
*/
sClient = accept(sServer, (sockaddr *)&addrClient, &addrClientlen);
if (INVALID_SOCKET == sClient){
printf("accept failed!,错误代码:%d\n", WSAGetLastError());
closesocket(sServer);
WSACleanup();
return -1;
}
std::cout << "已连接"<<endl;
//循环接收客户端的数据
while (true)
{
//char msg[BUFFER_SIZE];
//gets_s(msg);
int command;
cin >> command;
err_code = send(sClient, (char *)&command, sizeof(int), 0);
if (command == 4)
{
char buffer[100]; //传送的字符串
int recList[10];
memset(buffer, 0, sizeof(buffer)); //清内存
memset(recList, 0, sizeof(recList));
//下面是接收字符串的代码
//第一个参数指客户端(另一端,绑定的是客户端的IP地址和端口)套接字描述符;第二个参数指明一个缓冲区,
//该缓冲区用来存放recv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置0。
err_code = recv(sClient, buffer, sizeof(buffer), 0);
//下面对字符串信息进行还原,将其变成我们的结构体数据
memcpy(recList, buffer, sizeof(recList)); //p1发送到了这边的p1
for (int i = 0; i < 10; i++)
{
cout << recList[i] << " ";
}
cout << endl;
if (err_code == SOCKET_ERROR) {
printf("Recv failed !,错误代码:%d\n", WSAGetLastError());
closesocket(sClient);
closesocket(sServer);
WSACleanup();
return -1;
}
}
else if (command == 2)
{
cout << "等待发送新的指令 : " << endl;
continue;
}
else if (command == 3)
{
cout << "结束" << endl;
break;
}
else {
cout << "指令有误,请重新发送!" << endl;
continue;
}
}
closesocket(sClient); //关闭用于通信的socket
closesocket(sServer);//关闭与本地地址绑定的socket
WSACleanup();//释放资源
system("pause");
return 0;
}