#include<WinSock2.h>
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<cstdlib>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
#define DEFAULT_PORT 5055
#define BUFFER_LENGTH 1024
class user
{
public:
user(string username, string ip, int sender_port, int receiver_port)
{
this->username = username;
this->ip = ip;
this->sender_port = sender_port;
this->receiver_port = receiver_port;
//设置接收器的地址
receiver.sin_family = AF_INET;
receiver.sin_port = htons(receiver_port);
char *addr = new char[ip.length() + 1];
strcpy(addr, ip.c_str());
receiver.sin_addr.s_addr = inet_addr(addr);
}
string username; //用户名
string ip; //客户端ip地址
int sender_port; //发送器端口
int receiver_port; //接收器端口
struct sockaddr_in receiver; //存储接收器的地址
};
class server
{
public:
bool Startup(); //检测是否满足服务器运行的环境
bool SetServerSocket(); //设置服务器用来监听信息的socket套接字
bool Checktxt(); //检测存储文件是否存在,若不存在,创建一个
void work(); //服务器运行的主函数
void SendMessage(string message, struct sockaddr_in x); //发送信息的函数
void Sendonlinelist(); //向客户端发送好友在线列表
bool TestUsernameAndPassword(string username, string password, int &flag); //测试用户名和密码是否正确
bool TestDuplicateLogin(string username); //测试是否重复登录
bool TestDuplicateRigister(string username); //测试是否重复注册
string Getusername(string ip, int port); //根据ip和端口号获得用户名
int Getuserindex(string username); //根据用户名获得用户在在线用户表的索引号
void extractLoginuserinfor(string userinfor, string &username, string &password, string &receiverport); //提取登录请求中的用户名密码和显示器端口号
void extractRegisteruserinfor(string userinfor, string&username, string&password); //提取注册请求中的用户名和密码
void extactPersonalMessageReceivername(string &message, string &receivername); //提取私聊消息中的接收者的姓名
private:
WSADATA wsaData;
SOCKET sSocket; //用来接收消息的套接字
struct sockaddr_in ser; //服务器地址
struct sockaddr_in cli; //客户地址
int cli_length = sizeof(cli); //客户地址长度
char recv_buf[BUFFER_LENGTH]; //接收数据的缓冲区
vector<user> usertable; //在线用户表
string sendmessage, printmessage; //存储服务器转发、打印用的字符串
int iSend, iRecv; //存储服务器发送和接收的字符串的长度
};
bool server::Startup()
{
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
cout << "Failed to load Winsock." << endl;
return false;
}
return true;
}
bool server::SetServerSocket()
{
//产生服务器端套接口
sSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (sSocket == INVALID_SOCKET)
{
cout << "socket()Failed:" << WSAGetLastError() << endl;
return false;
}
//建立服务器端地址
ser.sin_family = AF_INET;
ser.sin_port = htons(DEFAULT_PORT); //htons()函数把一个双字节主机字节顺序的数转换为网络字节顺序的数
ser.sin_addr.s_addr = htonl(INADDR_ANY); //htonl()函数把一个主机字节顺序的数转换为网络字节顺序的数
if (bind(sSocket, (LPSOCKADDR)&ser, sizeof(ser)) == SOCKET_ERROR)
{
cout << "bind()Failed:" << WSAGetLastError() << endl;
return false;
}
return true;
}
void server::SendMessage(string message, struct sockaddr_in x)
{
char *send_buf = new char[message.length() + 1];
strcpy(send_buf, message.c_str());
SOCKET rSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (rSocket == INVALID_SOCKET)
{
cout << "socket()Failed:" << WSAGetLastError() << endl;
return;
}
cout<<"服务器发消息给客户端之前"<<endl;
cout<<"消息为"<<send_buf<<endl;
iSend = sendto(rSocket, send_buf, message.length() + 1, 0, (struct sockaddr*)&(x), sizeof(x));
cout<<"服务器发消息给客户端之后,iSend="<<iSend<<endl;
if (iSend == SOCKET_ERROR)
{
cout << "sendto failed:" << WSAGetLastError() << endl;
closesocket(rSocket);
return;
}
closesocket(rSocket);
}
void server::Sendonlinelist()
{
string onlinelist;
for (int i = 0; i < usertable.size(); i++)
onlinelist = onlinelist + usertable[i].username + "#";
onlinelist = onlinelist + "$"; //结束标志
SendMessage(onlinelist, cli);
}
bool server::TestUsernameAndPassword(string username, string password, int &flag)
{
if (!Checktxt())
{
cout << "无法找到存储文件." << endl << endl;
flag = 0; //未找到用户名的标志
return false;
}
fstream in("C:\\userform\\userform.txt");
string line;
string username_txt, password_txt;
while (getline(in, line))
{
for (int i = 0; i < line.size(); i++)
{
if (line[i] == '#')
{
username_txt = line.substr(0, i);
password_txt = line.substr(i + 1);
break;
}
}
if (username_txt == username) //该用户名存在
{
if (password == password_txt) //且密码正确
{
in.close();
return true; //返回验证成功
}
cout << "用户" << username << "登录密码错误" << endl << endl; //返回密码错误的信息
flag = 1; //密码错误的标志
return false;
}
}
in.close();
cout << "未注册过的用户:" << username << endl << endl;
flag = 0; //未找到用户名的标志
return false;
}
bool server::TestDuplicateLogin(string username)
{
int i;
for (i = 0; i < usertable.size(); i++)
if (usertable[i].username == username) break;
if (i == usertable.size()) //该用户还没有登录过
return false;
else
{
cout << "用户" << username << "重复登录" << endl;
return true;
}
}
bool server::TestDuplicateRigister(string username)
{
if (!Checktxt())
{
cout << "无法找到存储文件." << endl << endl;
return true;
}
fstream in("C:\\userform\\userform.txt");
string line;
while (getline(in, line))
{
string username_txt;
for (int i = 0; i < line.size(); i++)
{
if (line[i] == '#')
{
username_txt = line.substr(0, i); //提取用户名
if (username_txt == username) //对比,相等则表明已经注册过
{
in.close();
cout << "用户名" << username << "重复注册" << endl << endl;
return true;
}
break; //否则继续对比下一个用户名
}
}
}
in.close();
return false; //代码执行到这说明该用户名还没有注册过
}
string server::Getusername(string ip, int port)
{
for (int i = 0; i < usertable.size(); i++)
if (usertable[i].ip == ip&&usertable[i].sender_port == port)
return usertable[i].username;
cout << "非法的用户连接上服务器" << endl;
cout << "ip地址为:" << ip << endl << "端口号为:" << port << endl;
return "";
}
int server::Getuserindex(string username)
{
int i = 0;
for (i = 0; i < usertable.size(); i++)
if (usertable[i].username == username) break;
return i;
}
void server::extractLoginuserinfor(string userinfor, string &username, string &password, string &receiverport)
{
int i;
for (i = 0; i < userinfor.length(); i++) //提取用户名
{
if (userinfor[i] == '#')
{
username = userinfor.substr(0, i);
break;
}
}
for (int j = i + 1; j < userinfor.length(); j++) //提取密码和显示器端口号
{
if (userinfor[j] == '#')
{
password = userinfor.substr(i + 1, j - i - 1);
receiverport = userinfor.substr(j + 1);
break;
}
}
}
void server::extra