p2p查询服务器

p2p查询服务器
p2p查询服务器

多线程得P2P实现

Phase 1: Establishing Client-Server Communications

1.题目要求

第一阶段要求实现一个多线程的C/S结构系统,主要实现了用户的四种功能,分别是登陆,上传文件,查询文件,退出。登陆需要对密码在客户端和服务器端分别加密和解密,如果匹配错误需要在客户端返回信息格式为LGINusername#password;上传文件可以支持多次上传,并且为文件指定端口号,格式为SHREportnumber#filename,在模拟数据库中存储文件相应得信息(文件只能是.txt)上传成功回服务器返回SHOK的信息;查询文件要求根据文件名,查询数据库中所有符合要求的文件并且输出格式设置为SRCHfilename# username #ip#port的信息,一次输出一条;退出命令执行时需要将用户上传得所有文件信息删除,然后关闭SOCKET。

2.开发环境

操作系统:windows XPp

编程语言:C

编译器:VC6.0

3.程序详解:

3.1Socket连接和数据库模拟

这里第一阶段主要是先实现Client和Server可以相互交流的功能,这里主调用的Windows的API函数来建立socket和连接client和server,函数listen监听,bind绑定socket和IP,accept用来创建连接的socket,然后通过send和recv函数来发送和接受数据。

数据库主要用了结构体来模拟,userid(username,pwd) usefile ( username , filename[][] ,port[][] ,ip)。Usefile采取的对应每一个用户开出一张表,这样的优点是在删除的时候比较节省时间,缺点是对硬盘有浪费,需要很多多余的开销。3.2登陆部分

这部分主要是客户端输入用户名密码,然后服务器验证返回的一个过程,首先这里需要对用户的密码采取一个加密得措施,公式为password=password-key,key为随机生成得0到9的int型数据,加密以后需要把key添加在密码的前面,使得服务器可以验证密码,需要注意得是key+48才是此int相对应得char型字符。服务器解码后取相应的部分到username和password,然后和已经初始化在

服务器端的用户列表(username,password)匹配,正确标记位flag置1,发送登陆成功信息到客户端,并且记录客户的ip和username,等待客户端输入下一步指令,错误返回登陆错误,提示用户输入正确信息。

3.3共享文件

登陆成功后才可以执行,这里用户输入格式为SHREport#filename#...#fileN/n 的命令,服务器端判断命令的首部字段,如果符合格式,对命令按字符扫描,记录port,判断#和/n两个分界点,取出filename,然后将等到的(filename,port)插入到相应用户的表中去。服务器端成功记录后返回SHOK到客户端通知客户共享成功。客户可以选择继续共享文件还是进入下一步操作,这里主要是通过对首部字段的判断来实现这个循环

3.4查询文件

共享文件结束后,可以通过输入格式为SRCHfilename/n的命令来查询相的的文件,这里服务器端口首先需要判断首部字段如果是SRCH进入SRCH模块然后取出filename,在数据库中进行匹配,每次匹配成功就生成一条信息,格式为SRESfilename#username#ip#port 然后发送给客户端,客户端判断信息如果只是SRES或者首部字段不是SRES就直接进行到下一阶段,除此之外说明服务器端还在继续发送搜索结果,则客户端继续recv直到收到的信息为SRES,在输入.txt时可以查询到所有服务器上的有效文件

3.5退出部分

这部分比较简单,但是一直贯穿在前面几个模块中,如果用户在任何一个阶段输入了QUIT指令,则都会出发QUIT部分,这里先通过前面记录下来得clientname对于用户自己的datafile表中的信息初始化,然后关闭socket

3.6多线程部分

本部分在服务器端得main函数中,当服务器端得接口监听到一个Client的请求就创建一个线程来处理这个Client

4.程序流程图

图1 登陆流程图

图2 文件共享流程图

图3 文件查询流程图

图4 QUIT过程流程图

5.程序源代码服务器端程序源码:

#include

#include

#include

#include

//用户账号表

struct userid

{

char *username;

char *pwd;

}user[3];

//用户文件表

struct usefile

{

char *username;

char filename[20][30];

char port[20][5];

char *ip;

}datafile[3];

#define eeee "/n"

#define LGINOK "LRES connection is OK !"

#define LGINER "EROR incorrect username and password,please input correct information!" #define LGIN "LGIN"

#define SHRE "SHRE"

#define WWWW '/0'

#define SHOK "SHOK"

#define SHREER "EROR upload failed"

#define SRCH "SRCH"

#define SRES "SRES/0"

#define SHARP "#"

#define FAIL "ERORcann`t find it"

#define QUIT "QUIT/0"

#define EXIT "EXIT"

#define TXT ".txt"

DWORD WINAPI ClientThread(LPVOID lpParam)

{

SOCKET NewConnection=(SOCKET)lpParam;

SOCKADDR_IN ClientAddr;

int ClientAddrLen= sizeof (ClientAddr);

char recvbuf[1500]={'/0'};

char sendbuf[1500]={'/0'};

int i=0,j=0,k=0;

char *shre="SHRE";

char *shes="SHES";

char *quit="QUIT";

//进入一次循环

while(1)

{

int i,count=0;

char recvbuf[1500]={'0'};

char sendbuf[1500]={'0'};

char clientname[6]={'/0'};

char clientpwd[5]={'/0'};

char head[5]={'/0'}; //首部字段

char port[5]={'/0'};

//char head2[4]={'/0'};

int flag=0; //标记本次登陆是否成功

int filenumber=0; //文件号

int usernumber=0; /用户号

//接受客户端信息,输出客户端信息

recv(NewConnection,recvbuf,1500,0);

strcpy(recvbuf+strlen(recvbuf),eeee);

printf("Client:");

printf("%s",recvbuf);

//登陆检查

for(i=0;i<4;i++)

head[i]=recvbuf[i]; //得到CLIENT发的信息的首部字段while((flag==0)&&(strcmp(head,QUIT)))

{

if(!strcmp(head,LGIN)) //校验ID,PWD

{

//解密,把USERNAME 和PWD都存入中间字符串中

int i=4,j=0,m=0,key;

key=recvbuf[10]-48;

for(j=0;j<4;j++)

{

recvbuf[10+j]=recvbuf[11+j]+key;

}

recvbuf[14]='/0';

for(j=0;j<5;j++,i++)

clientname[j]=recvbuf[i];

for(j=0;j<4;j++,i++)

//匹配用户和密码

for(i=0;i<3;i++)

{

if(!strcmp(clientname,user[i].username))

{

if(!strcmp(clientpwd,user[i].pwd))

flag=1;

}

}

printf("%d",flag);

if(flag==1) //成功传输OK

{

printf("Server:");

printf("%s",LGINOK);

strcpy(sendbuf,LGINOK);

send(NewConnection,sendbuf,1500,0);

printf("/n");

break;

}

else //失败传输EROR

{

printf("Server:");

printf("%s",LGINER);

strcpy(sendbuf,LGINER);

send(NewConnection,sendbuf,1500,0);

printf("/n");

}

}

if(strcmp(head,LGIN))

{

printf("Server:");

printf("%s",LGINER);

strcpy(sendbuf,LGINER);

send(NewConnection,sendbuf,1500,0);

}

for(i=0;i<1500;i++)

{

recvbuf[i]='/0';

sendbuf[i]='/0';

}

recv(NewConnection,recvbuf,1500,0);

strcpy(recvbuf+strlen(recvbuf),eeee);

printf("Client:");

printf("%s",recvbuf);

//登陆检查

for(i=0;i<4;i++)

head[i]=recvbuf[i];

}

//第二部分文件传输

if(flag==1)

{

for(i=0;i<3;i++)

{

if(!strcmp(clientname,datafile[i].username))

usernumber=i;

}

//发送共享文件操作

//初始化RECVBUF和SENDBUF

for(i=0;i<1500;i++)

{

recvbuf[i]='/0';

sendbuf[i]='/0';

}

recv(NewConnection,recvbuf,1500,0);

strcpy(recvbuf+strlen(recvbuf),eeee);

printf("Client:");

printf("%s",recvbuf);

//首部字段判断

head[i]=recvbuf[i];

}

//多次SHRE

while(!strcmp(head,SHRE)&&(flag==1))

{

if((flag==1)&&(!strcmp(head,SHRE))&&(recvbuf[8]=='#')&&(filenumber<=19)) //登陆成功并且首部字段为SHRE3333#,将(文件,端口号)录入数据库

{

i=9;

for(i=4;i<8;i++)

port[i-4]=recvbuf[i];

datafile[usernumber].ip=inet_ntoa(ClientAddr.sin_addr);

//记录用户IP进入表

while(recvbuf[i]!='/n')

{

char temfilename[30]={'/0'};

int j=0;

while((recvbuf[i]!='#')&&(recvbuf[i]!='/n'))

{

temfilename[j]=recvbuf[i];

i++;

j++;

}

//添加该文件到该用户的文件表

strcpy(datafile[usernumber].filename[filenumber],temfilename);

strcpy(datafile[usernumber].port[filenumber],port);

filenumber++;

if(recvbuf[i]!='/n')

i++;

}

printf("Server:");

printf("%s",SHOK);

strcpy(sendbuf,SHOK);

send(NewConnection,sendbuf,1500,0);

}

else

{

printf("Server:");

printf("%s",SHREER);

strcpy(sendbuf,SHREER);

send(NewConnection,sendbuf,1500,0);

printf("/n");

}

for(i=0;i<1500;i++)

{

recvbuf[i]='/0';

sendbuf[i]='/0';

}

recv(NewConnection,recvbuf,1500,0);

strcpy(recvbuf+strlen(recvbuf),eeee);

printf("Client:");

printf("%s",recvbuf);

//首部字段判断

for(i=0;i<4;i++)

head[i]=recvbuf[i];

}

//第三部份搜索部分

//初始化发送BUF 否则BUF中又SHOK等信息

for(i=0;i<1500;i++)

{

sendbuf[i]='/0';

}

while(!strcmp(head,SRCH))

{

if((flag==1)&&(!strcmp(head,SRCH))&&(strlen(recvbuf)>6))

{

char temsrchfile[31]={'/0'};

int sign=0,m; //找到的标记位;

i=4;

//取文件名

while(recvbuf[i]!='/n'&&(i<35))

{

temsrchfile[i-4]=recvbuf[i];

i++;

}

if(!strcmp(temsrchfile,TXT))

{

for(i=0;i<3;i++)

{

for(j=0;j<20;j++)

{

for(m=0;m<1500;m++)

{

sendbuf[m]='/0';

}

sign=1;

if(datafile[i].filename[j][0]!='/0')

{

strcpy(sendbuf+strlen(sendbuf),SRES);

strcpy(sendbuf+strlen(sendbuf),datafile[i].filename[j]);

strcpy(sendbuf+strlen(sendbuf),SHARP);

strcpy(sendbuf+strlen(sendbuf),datafile[i].username);

strcpy(sendbuf+strlen(sendbuf),SHARP);

strcpy(sendbuf+strlen(sendbuf),datafile[i].ip);

strcpy(sendbuf+strlen(sendbuf),SHARP);

strcpy(sendbuf+strlen(sendbuf),datafile[i].port[j]);

strcpy(sendbuf+strlen(sendbuf),eeee);

send(NewConnection,sendbuf,strlen(sendbuf),0);

printf("Server:");

printf("%s",sendbuf);

printf("/n");

}

}

}

}

//在数据库中查找符合目标得文件,并且输出到屏幕上发送标记位记录else{

for(i=0;i<3;i++)

{

for(j=0;j<20;j++)

{

for(m=0;m<1500;m++)

{

sendbuf[m]='/0';

}

if(!strcmp(temsrchfile,datafile[i].filename[j]))

{

sign=1; //标记找到知道一条;

//制作输出找到的信息

strcpy(sendbuf+strlen(sendbuf),SRES);

strcpy(sendbuf+strlen(sendbuf),datafile[i].filename[j]);

strcpy(sendbuf+strlen(sendbuf),SHARP);

strcpy(sendbuf+strlen(sendbuf),datafile[i].username);

strcpy(sendbuf+strlen(sendbuf),SHARP);

strcpy(sendbuf+strlen(sendbuf),datafile[i].ip);

strcpy(sendbuf+strlen(sendbuf),SHARP);

strcpy(sendbuf+strlen(sendbuf),datafile[i].port[j]);

strcpy(sendbuf+strlen(sendbuf),eeee);

send(NewConnection,sendbuf,strlen(sendbuf),0);

printf("Server:");

printf("%s",sendbuf);

printf("/n");

}

}

}

}

//清空SENDBUF

for(i=0;i<1500;i++)

{

sendbuf[i]='/0';

}

if(sign==1)

{

strcpy(sendbuf,SRES);

send(NewConnection,sendbuf,1500,0);

printf("Server:");

printf("%s",sendbuf);

printf("/n");

}

else

{

printf("Server:");

printf("%s",FAIL);

strcpy(sendbuf,FAIL);

send(NewConnection,sendbuf,strlen(sendbuf),0);

printf("/n");

}

//继续输入

for(i=0;i<1500;i++)

{

recvbuf[i]='/0';

sendbuf[i]='/0';

}

recv(NewConnection,recvbuf,1500,0);

strcpy(recvbuf+strlen(recvbuf),eeee);

printf("Client:");

printf("%s",recvbuf);

//首部字段判断

for(i=0;i<4;i++)

head[i]=recvbuf[i];

}

else

{

printf("Server:");

printf("%s",FAIL);

strcpy(sendbuf,FAIL);

send(NewConnection,sendbuf,strlen(sendbuf),0);

printf("/n");

for(i=0;i<1500;i++)

{

recvbuf[i]='/0';

sendbuf[i]='/0';

}

recv(NewConnection,recvbuf,1500,0);

strcpy(recvbuf+strlen(recvbuf),eeee);

printf("Client:");

printf("%s",recvbuf);

//首部字段判断

for(i=0;i<4;i++)

head[i]=recvbuf[i];

}

if(!strcmp(head,QUIT))

break;

}

//第四部分QUIT单元

if(!strcmp(head,QUIT))

{

int m=0;

j=0;

//清空数据库

for(i=0;i<3;i++)

{

if(!strcmp(clientname,datafile[i].username))

{

datafile[i].ip="/0";

for(j=0;j<20;j++)

{

for(m=0;m<30;m++)

{

datafile[i].filename[j][m]='/0';

}

for(m=0;m<5;m++)

{

datafile[i].filename[j][m]='/0';

}

}

}

}

//发送结束信息

strcpy(sendbuf,EXIT);

send(NewConnection,sendbuf,strlen(sendbuf),0);

//closesocket(NewConnection);

break;

}

}

}

void main(void){

WSADA TA wsaData;

SOCKET ListeningSocket;

SOCKET NewConnection;

SOCKADDR_IN ServerAddr;

SOCKADDR_IN ClientAddr;

int port=8058;

int i,j,k,ret,iAddrSize;

HANDLE clientThread;

DWORD clientThreadId;

//用户ID表初始化

user[0].username="user0/0";

user[1].username="user1/0";

user[2].username="user2/0";

user[0].pwd="pwd0/0";

user[1].pwd="pwd1/0";

user[2].pwd="pwd2/0";

//数据库初始化

for(i=0;i<3;i++)

{

datafile[i].username=user[i].username;

datafile[i].ip="/0";

for(j=0;j<20;j++)

for(k=0;k<30;k++)

{

datafile[i].filename[j][k]='/0';

datafile[i].port[j][k]='/0';

}

}

//监听socket

WSAStartup(MAKEWORD(2,2),&wsaData);

ListeningSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); ServerAddr.sin_family = AF_INET;

ServerAddr.sin_port = htons(port);

ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(ListeningSocket,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr)); listen(ListeningSocket,5);

//多线程等待创建socket

while(1)

{

iAddrSize =

sizeof(ClientAddr); NewConnection=accept(ListeningSocket,(SO

CKADDR*)&ClientAddr,&iAddrSize);

if(NewConnection==INV ALID_SOCKET)

{

printf("accept() failed:%d/n",WSAGetLastError());

break;

}

printf("Acceptedclient :%s:%d/n",inet_ntoa(Clie ntAddr.sin_addr),ntohs(ClientAddr.sin_port));

clientThread=CreateThread(NULL,0,ClientThread,(LPVOID)NewCo nnection,0,&clientThreadId);

if(clientThread==NULL)

{

printf("createthreaad()failed:%d/n",GetLastError());

break;

}

CloseHandle(clientThread);

}

closesocket(ListeningSocket);

WSACleanup();

return;

}

以下是客户端程序源码:

#include

#include

#include

#include

#define QUIT "EXIT"

void main(void)

#define SRES "SRES/0"

#define EROR "EROR"

#define LGIN "LGIN/0"

{

WSADA TA wsaData;

SOCKET s;

SOCKADDR_IN ServerAddr;

int Port = 8058,i;

char recvbuf[1500]={'/0'};

char sendbuf[1500]={'/0'};

char head[5]={'/0'};

//建立连接

WSAStartup(MAKEWORD(2,2),&wsaData);

s = socket (AF_INET,SOCK_STREAM,IPPROTO_TCP);

ServerAddr.sin_family =AF_INET;

ServerAddr.sin_port = htons(Port);

ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

connect(s,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr));

printf("please enter the username and password as the form :LGINusername#password/n");

while(1)

{

int key=0;

for(i=0;i<1500;i++)

{

recvbuf[i]='/0';

sendbuf[i]='/0';

}

printf("Client:");

scanf("%s",sendbuf);

//加密

for(i=0;i<4;i++)

{

head[i]=sendbuf[i];

}

if(!strcmp(head,LGIN))

{

char tem;

srand((unsigned)time(NULL));

key = rand() % 10;

if(strlen(sendbuf)>10)

{

for(i=13;i>=10;i--)

{

tem=sendbuf[i]-key;

sendbuf[i+1]=tem;

}

sendbuf[10]=key+48;

}

send(s,sendbuf,1500,0);

}

else

{

send(s,sendbuf,1500,0);

}

//判断QUIT

if(!strcmp(sendbuf,QUIT))

break;

//多次自动接受SRES结果

do{

recv(s,recvbuf,1500,0);

for(i=0;i<4;i++)

相关主题
相关文档
最新文档