📄 server.cpp
字号:
#include<Winsock2.h>
#include<iostream.h>
#include<windows.h>//创建线程
#include<stdlib.h>
#include<stdio.h>
#include <process.h>//处理线程的头文件
#include<fstream.h>//处理读写文件的操作
#pragma comment (lib,"ws2_32")
char *buffer;
CRITICAL_SECTION rec_cs;
CRITICAL_SECTION send_cs;
FD_SET listen1;// 已经登录或者注册成功的客户端的IP
SOCKET server;
int innitional()
{
//与客服端基本一样
int i;
WORD version;
WSADATA data;
version=MAKEWORD(2,2);
int err=WSAStartup(version,&data);
if(err!=0)
{
cout<<"初始化失败"<<endl;
exit(0);
}
else
cout<<"初始化成功"<<endl;
server=socket(AF_INET,SOCK_STREAM,0);
if(server==INVALID_SOCKET)
{
cout<<"获取服务器套接字错误"<<endl;
exit(0);
}
sockaddr_in localserver;
localserver.sin_family=AF_INET;
localserver.sin_port=htons(6000);//设置端口号,应该与客服端的一致;
localserver.sin_addr.s_addr=INADDR_ANY;
int err1=bind(server,(sockaddr *)&localserver,sizeof(localserver));//绑定
if(err1!=0)
{
cout<<"绑定失败"<<endl;
exit(0);
}
int err2=listen(server,100);//对端口进行监听
if(err2==0)
{
cout<<"服务器处于监听中……"<<endl;
i=0;
}
else
{
cout<<"无法进行监听………"<<endl;
i=1;
exit(0);
}
return i;
}
//////////////////////////////////////////////////////////////////////////////
int writefile(char *name)
{
//进行写文件的操作
fstream writefile("1.txt",ios::app);
if(!writefile)
{
cout<<"打开文件失败"<<endl;
return 1;
}
//由于客户端发过来的消息里面前两个字符是标识用户到底是想注册还是登录,所以在写入文件的时候应该去掉
int length=strlen(name);
char *name_password;
name_password=new char[];
for(int i=2;i<length;i++)
{
name_password[i-2]=name[i];
}
writefile<<name_password<<endl;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
int readfile(char *str)
{
char *user;
user=new char[];
//去掉用户发过来的消息的前两个字符
for(int i=2;i<=strlen(str);i++)
{
user[i-2]=str[i];
}
fstream readfile("1.txt",ios::in);
if(!readfile)
{
return 0;
}
char s[13];
readfile.seekg(0);
while(!readfile.eof())
{
readfile.getline(s,sizeof(s));
if(strcmp(user,s)==0)
{
return 0;//查找成功返回值0
}
}
return 1;//失败的时候返回1
}
//////////////////////////////////////////////////////////////////////////////
void WINAPI send_rec()
{
//接受与分发客户端发过来的消息
FD_ZERO(&listen1);
FD_SET readonly;
int connectting;
FD_ZERO(&readonly);
while(1)
{
{
readonly=listen1;
EnterCriticalSection(&send_cs);
struct timeval timeout={1,0};
do
{
connectting=select(NULL,&readonly,NULL,NULL,&timeout);// 利用Select函数来进行阻塞
}while(connectting==0);
if(listen1.fd_count>0)//判断此时有没有客户连接
{
for(int i=0;i<=listen1.fd_count;i++)
{
if(FD_ISSET(listen1.fd_array[i],&readonly))
{
SOCKET sendall=listen1.fd_array[i];
recv(sendall,buffer,1000,0);
if(strcmp(buffer,"esc")==0)
{
//FD_CLR(listen1.fd_array[i],&listen1);
printf("有人下线了\n");
closesocket(listen1.fd_array[i]);
listen1.fd_count--;
break;
}
else
{
printf("%s\n",buffer);
// FD_CLR(listen1.fd_array[i],&readonly);
{
if(listen1.fd_count>0)
{
for(int j=0;j<listen1.fd_count;j++)
{
send(listen1.fd_array[j],buffer,1000,0);//循环发送消息
//FD_CLR(listen1.fd_array[i],&readonly);
}
}
}
}
}
}
}
LeaveCriticalSection(&send_cs);//离开临界区
}
}
}
/////////////////////////////////////////////////////////////////////////
void main()
{
int j;
buffer=new char[];//初始化各个变量
j=innitional();
FD_SET serverread;
FD_SET serverreadonly;
FD_ZERO(&serverread);
FD_ZERO(&serverreadonly);//起到清空套接字集合的作用
FD_SET(server,&serverread);
HANDLE RECHANDLE;
DWORD RECID;
Sleep(10000);
RECHANDLE=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)send_rec,NULL,0,&RECID);//创建接收与转发消息的线程
InitializeCriticalSection(&send_cs);//利用注册于登录线程与接收转发线程互斥,而下面通过判断语句来达到写文件与读文件的互斥
InitializeCriticalSection(&rec_cs);
while(1)
{
serverreadonly=serverread;
int connectserver=select(NULL,&serverreadonly,NULL,NULL,NULL);//利用Select函数来进行阻塞, 如果有可读消息的时候不阻塞
EnterCriticalSection(&send_cs);
if(connectserver==1)
{
//如果有用户发起了连接操作
for(int i=0;i<serverreadonly.fd_count;i++)
{
if(FD_ISSET(serverread.fd_array[0],&serverreadonly))
{
SOCKET wildclient;
sockaddr_in from;
int fromlen=sizeof(from);
wildclient=accept(server,(struct sockaddr *)&from,&fromlen);//接收来自客服端的注册或者登录信息
FD_SET(wildclient,&serverread);//将现在有connect操作的套接字写入到serverread
}
if(FD_ISSET(serverread.fd_array[i+1],&serverreadonly))
{
SOCKET recall=serverread.fd_array[i+1];
recv(recall,buffer,1000,0);
char *name;
name=new char[];
for(int m=2;m<strlen(buffer);m++)
{
int i=m-2;
name[i]=buffer[m];
if(name[i]=='#')
{
name[i]='\0';
break;
}
}
if(buffer[0]=='1')
{
int flagw=writefile(buffer);//将注册信息写入文件当中
if(flagw==0)
{
send(recall,"succedreg",10,0);//注册成功返回成功的消息给客户端
FD_SET(recall,&listen1);//将注册成功的套接字写入要进行分发消息的套接字集合
FD_CLR(recall,&serverread);// 将recall套接字从临时套接字集合清除
FD_CLR(recall,&serverreadonly);
printf(name);
printf("上线了\n");// 输出提示信息
}
else
{
send(recall,"failregit",10,0);//注册失败返回提示信息
FD_CLR(recall,&serverread);
FD_CLR(recall,&serverreadonly);
}
}
if(buffer[0]=='2')
{
//响应客服端的登录操作
int falg1=readfile(buffer);
if(falg1==0)
{
send(recall,"succedreg",10,0);
FD_SET(recall,&listen1);// 将登录成功的套接字写入要进行聊天的套接字集合
FD_CLR(recall,&serverread);
FD_CLR(recall,&serverreadonly);
printf(name);
printf("上线了\n");
}
if(falg1==1)
{
send(recall,"failregit",10,0);//登录失败的时候返回提示信息
FD_CLR(recall,&serverread);
FD_CLR(recall,&serverreadonly);
}
}
}
}
}
else
{
if(FD_ISSET(serverread.fd_array[0],&serverreadonly))
{
SOCKET wildclient;
sockaddr_in from;
int fromlen=sizeof(from);
wildclient=accept(server,(struct sockaddr *)&from,&fromlen);//接收来自客服端的注册或者登录信息
FD_SET(wildclient,&serverread);//将现在有connect操作的套接字写入到serverread
}
}
LeaveCriticalSection(&send_cs);
}
}
/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -