- 论坛徽章:
- 0
|
有一个服务器和两个客户端,客户端是命令行模式,客户端之间发送的消息要经过服务器处理然后再转发,客户端主线程(main)里用while(1)等待命令输入,然后根据相应的命令在进行操作,另外还建立了一个子线程CreateThread(NULL,0,ReadSock,NULL,0,NULL);用来接收服务器发来的消息, 根据不同的消息类型做相应的响应,现在有一个这样的问题:
在创建的线程里,我要和用户进行交互,(输入Y或者N),问题就出来了,在子线程里用getchar()进行输入时,总是提示无效的命令格式,也就是说,建立的线程里用户输入的字符被当作了命令,请问这种问题怎么解决!
把源程序贴上:
ChatClient.h
#include "windows.h"
class ChatClient
{
public:
ChatClient(void);
~ChatClient(void);
BOOL InitConnect(UINT port,char *serverIP,UINT port1,char *clientIP);
public:
SOCKET m_servSocket; // 服务器socket
sockaddr_in m_addrServ; // 保存服务器信息
// 用户信息
char m_userName[17]; // 用户名
LONGLONG m_UserID; // 用户ID
char m_Password[11]; // 用户密码
// 服务器信息
char m_serverIP[20]; // 服务器IP
UINT m_servPort; // 服务器端口
// 密码策略
char encodeType[6]; // 保存编码顺序,某次编码不存在时,用'-'表示
short encodeN[6]; // 若为栅栏编码时,则此数组中对应位置保存栅栏排数,范围1~1024;否则,为0
// 客户端信息
sockaddr_in m_addrClient; // 保存客户端信息
char m_clientStrIP[20]; // 用于指定客户端通信所用IP
UINT m_clientPort; // 用于指定客户端通信所有端口
};
// 通信消息格式
typedef struct Message
{
LONGLONG userID[10]; // 用户ID信息数组
BYTE msgType; // 消息类型
BYTE userName[17]; // 用户名
BYTE buf[1950]; // 登录、注册时用于保存密码;聊天时,用于存放聊天信息
}MESSAGE;
typedef struct FileTrans // 文件传输
{
char serverIP[20];
UINT serverPort;
LONGLONG destID; // 接收端ID
LONGLONG srcID; // 发送端ID
BYTE fileName[512];
BYTE buf[1950];
}FILETRANS;
console.cpp
#include "ChatClient.h"
#include "CodePro.h"
#include <iostream>
#include <fstream>
using namespace std;
ChatClient cc;
MESSAGE msg;
DWORD WINAPI ReadSock(PVOID pVOID);
BYTE Log_Reg=0;
LONGLONG OLuserID[10];
CodePro codePro;
int main(int argc, char* argv[])
{
if ( argc < 6 || argc > 9 )
{
printf("格式输入出错!\n命令格式:console reg|log USER_ID PASSWORD [USER_NAME] SERV_IP SERV_PORT [CLIENT_IP] [CLIENT_PORT]" ;
return 1;
}
if ( strcmp(argv[1],"reg" && strcmp(argv[1],"log" )
{
printf("格式输入出错!\n命令格式:console reg|log USER_ID PASSWORD [USER_NAME] SERV_IP SERV_PORT [CLIENT_IP] [CLIENT_PORT]" ;
return 1;
}
cc.m_UserID=(LONGLONG)_atoi64(argv[2]); //
strcpy(cc.m_Password,argv[3]); // 保存用户密码
if (strcmp(argv[1],"reg" ==0) // 注册
{
if ( argc!=7 && argc!=9 )
{
printf("格式输入出错!\n命令格式:console reg|log USER_ID PASSWORD [USER_NAME] SERV_IP SERV_PORT [CLIENT_IP] [CLIENT_PORT]" ;
return 1;
}
strcpy(cc.m_userName,argv[4]);
strcpy(cc.m_serverIP,argv[5]);
cc.m_servPort=atoi(argv[6]);
if( argc == 9 )
{
strcpy(cc.m_clientStrIP,argv[7]);
cc.m_clientPort=atoi(argv[8]);
}
else
strcpy(cc.m_clientStrIP,"不指定" ;
}
else // 登录
{
if ( argc!=6 && argc!=8 )
{
printf("4格式输入出错!\n命令格式:console reg|log USER_ID PASSWORD [USER_NAME] SERV_IP SERV_PORT [CLIENT_IP] [CLIENT_PORT]" ;
return 1;
}
strcpy(cc.m_serverIP,argv[4]);
cc.m_servPort=atoi(argv[5]);
if( argc == 8 )
{
strcpy(cc.m_clientStrIP,argv[6]);
cc.m_clientPort=atoi(argv[7]);
}
else
strcpy(cc.m_clientStrIP,"不指定" ;
}
if( !strcmp(argv[1],"log" )
{
Log_Reg=1;
}
cc.InitConnect(cc.m_servPort, cc.m_serverIP, cc.m_clientPort, cc.m_clientStrIP);
CreateThread(NULL,0,ReadSock,NULL,0,NULL);
memset(&msg,0,sizeof(MESSAGE));
msg.msgType=Log_Reg;
msg.userID[0]=cc.m_UserID;
strcpy((char *)msg.userName,cc.m_userName);
strcpy((char *)msg.buf,cc.m_Password);
send(cc.m_servSocket,(char *)&msg,sizeof(MESSAGE),0);
while(1)
{
char raw[128];
char buffer[128];
memset(buffer,0,12 ;
memset(raw,0,12 ;
gets(raw);
strcpy(buffer,raw);
// 命令参数分割
int paramc=0; // 参数个数
char paramv[10][50]; // 参数内容
char *cur;
char *next;
if( cur=strtok_s(buffer," \t",&next) )
{
strcpy_s(paramv[paramc],cur);
paramc++;
}
while( cur=strtok_s(NULL," \t",&next) )
{
strcpy_s(paramv[paramc],cur);
paramc++;
}
// 发送修改密码消息
if( !strcmp(paramv[0],"passwd"))
{
char oldPass[11];
char newPass[11];
memset(&msg,0,sizeof(MESSAGE));
msg.msgType=3;
msg.userID[0]=cc.m_UserID;
strcpy(oldPass,paramv[1]);
strcpy(newPass,paramv[2]);
strcpy((char *)msg.buf,oldPass);printf("old=%s\n",oldPass);
strcpy((char *)msg.userName,newPass);printf("new=%s\n",newPass);
send(cc.m_servSocket,(char *)&msg, sizeof(MESSAGE),0);
}
// 发送修改加密策略消息
else if(!strcmp(paramv[0],"cat"))
{
memset(&msg,0,sizeof(MESSAGE));
msg.msgType=4;
strcpy((char *)msg.buf,paramv[1]);
for(int i=0;i<6;i++)
{
msg.userID=paramv[2]-'0';
}
send(cc.m_servSocket,(char *)&msg, sizeof(MESSAGE),0);
}
// 退出程序
else if(!strcmp(paramv[0],"quit"))
{
return 0;
}
// 发送聊天消息
else if(!strcmp(paramv[0],"send"))
{
// 查找在线用户列表是否包含目标用户
LONGLONG drtUserID=_atoi64(paramv[1]);
int i;
for( i=0;i<10;i++)
{
if(OLuserID==drtUserID)
break;
}
if(i>=10)
{
printf("该用户当前不在线\n");
}
else
{
memset(&msg,0,sizeof(MESSAGE));
msg.msgType=2;
msg.userID[1]=cc.m_UserID;
msg.userID[0]=drtUserID;
strcpy((char *)msg.buf,strstr(raw,paramv[2]));
//////////////////////////////////////////////////////////////////////////
// 根据密码策略进行加密:加密结果放置msg.buf中
memcpy( codePro.input, msg.buf, 1950);
codePro.len = strlen(codePro.input);
for ( int i = 0; i < 6; i++ )
{
codePro.CodeInput = cc.encodeType;
codePro.FenceNums = cc.encodeN;
}
codePro.encode();
memcpy( msg.buf, codePro.input, 1950 );
send(cc.m_servSocket,(char *)&msg, sizeof(MESSAGE),0);
}
}
// 查找在线用户
else if(!strcmp(paramv[0],"look"))
{
cout<<"在线用户:\t";
for(int i=0;i<10;i++)
{
if(OLuserID<0)
break;
cout<<OLuserID<<"\t";
}
cout<<endl;
}
else if(!strcmp(paramv[0],"sendfile")) // 传输文件
{
//////////////////////////////////////////////////////////////////////////
if(paramc<3)
{
cout<<"格式不正确"<<endl;
cout<<"正确格式:sendfile [recvID] [filepath+filename]"<<endl;
}
else
{
// 检查制定目录下文件是否存在
ifstream pfile;
pfile.open(paramv[2]/*"c:\\1.txt"*/);
if(!pfile.is_open())
{
cout<<"File does not exits ! please input again."<<endl;
}
else
{
pfile.close();
// 检查接收端在不在线
BOOL flag=FALSE;
for(int i=0;i<10;i++)
{
if(OLuserID<0)
break;
if(OLuserID==_atoi64(paramv[1]))
{
flag=TRUE;
break;
}
}
if(flag==FALSE)
{
cout<<"接收用户当前不在线,请重新选择用户。"<<endl;
}
// 向服务器发送传文件请求
Message msg;
msg.msgType = 5; // 发送文件请求消息
msg.userID[0] = _atoi64(paramv[1]); // 接收端ID
msg.userID[1] =cc.m_UserID; // 发送端ID
memcpy(msg.buf,paramv[2],strlen(paramv[2])); // 文件路径+文件名
while(send(cc.m_servSocket,(char *)&msg,sizeof(MESSAGE), 0)<sizeof(MESSAGE))
{
cout<<"文件传输请求发送失败,是否重新发送请求?(Y/N)"<<endl;
if(getchar()=='N')
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
}
else if(!strcmp(paramv[0],"showme")) // 显示本机ID
{
cout<<"本机ID: "<< cc.m_UserID<<endl;
}
else if(!strcmp(paramv[0],"help")) // 帮助信息
{
cout<<"各命令以及格式:"<<endl;
cout<<"1 passwd:修改密码消息 "<<endl;
cout<<"2 cat: 修改加密策略"<<endl;
cout<<"3 quit: 退出"<<endl;
cout<<"4 send: 发送消息"<<endl;
cout<<"5 look: 查找在线用户"<<endl;
cout<<"6 senfile: 传输文件"<<endl;
cout<<"7 showme:查看本机ID"<<endl;
}
// 未定义
else
{
printf("未知的命令类型\n");
}
//////////////////////////////////////////////////////////////////////////
// recv(cc.m_servSocket,(char *)&msg,sizeof(MESSAGE),0); // 当有文件传输请求时
//////////////////////////////////////////////////////////////////////////
}
return 0;
}
// 接收服务器端消息函数
DWORD WINAPI ReadSock(PVOID pVOID)
{
fd_set fdR;
struct timeval timeout;
timeout.tv_sec=1;
timeout.tv_usec=0;
MESSAGE msg;
while(1)
{
FD_ZERO(&fdR);
FD_SET(cc.m_servSocket,&fdR);
switch(select(cc.m_servSocket,&fdR,NULL,NULL,&timeout))
{
case -1:
printf("select error\n");
return FALSE;
case 0:
break;
default:
if(FD_ISSET(cc.m_servSocket,&fdR))
{
memset(&msg,0,sizeof(MESSAGE));
recv(cc.m_servSocket,(char *)&msg,sizeof(MESSAGE),0);
// 对接收到你消息分类处理
// ID已被注册
if ( msg.msgType == 0 )
{
for(int i=0;i<10;i++)
{
OLuserID=-1;
}
closesocket(cc.m_servSocket);
cc.m_servSocket=NULL;
printf("[系统提示] 该ID已被注册,请重新注册或登录!\n");
//_exit(1);
}
// 在线用户ID列表更新
if ( msg.msgType == 1 || msg.msgType == 2 )
{
// 显示新的在线用户ID列表
for(int i=0;i<10;i++)
{
OLuserID=-1;
}
for ( int i = 0; i < 10; i++ )
{
if ( msg.userID == -1 )
break;
OLuserID=msg.userID;
}
// 显示系统提示信息
if ( msg.msgType == 1 )
printf("[系统提示] 有用户上线,在线用户ID列表已更新!\n");
else
printf("[系统提示] 有用户离线,在线用户ID列表已更新!\n");
}
// 各种登录失败消息
if ( msg.msgType == 3 || msg.msgType == 4 || msg.msgType == 5 ||
msg.msgType == 7 || msg.msgType == 8 || msg.msgType == 10 )
{
for(int i=0;i<10;i++)
{
OLuserID=-1;
}
closesocket(cc.m_servSocket);
cc.m_servSocket=NULL;
if ( msg.msgType == 3 )
printf("[系统提示] 登录失败,该用户ID不存在!\n");
if ( msg.msgType == 4 )
printf("[系统提示] 登录失败,登录密码错误!\n");
if ( msg.msgType == 5 )
printf("[警告信息] 该用户在别处登录,用户被迫强制下线\n");
if ( msg.msgType == 7 )
printf("[警告信息] 登录失败:服务器达到用户连接使用上限!\n");
if ( msg.msgType == 8 )
{
printf("[系统提示] 注册成功!\n");
printf("[警告信息] 登录失败:服务器达到用户连接使用上限!\n");
}
if ( msg.msgType == 10 )
printf("密码修改成功,请用新密码重新登录\n");
_exit(1);
}
// 聊天消息
if ( msg.msgType == 6 )
{
//////////////////////////////////////////////////////////////////////////
// 根据个人密码策略,对接收到的数据进行解密
memcpy(codePro.input, msg.buf, 1950 );
for ( int i = 0; i < 6; i++ )
{
codePro.CodeInput = cc.encodeType[5-i];
codePro.FenceNums = cc.encodeN[5-i];
}
codePro.decode();
memcpy(msg.buf, codePro.input, 1950);
cout<<"recv "<<msg.userID[1]<<" "<<msg.buf<<endl;
}
// 密码修改失败消息
if ( msg.msgType == 9 )
{
printf("[系统提示] 旧密码输入错误,密码修改失败!\n");
}
// 个人密码策略设置更新成功消息
if ( msg.msgType == 11 )
{
for ( int i = 0; i < 6; i++ )
{
cc.encodeType = (char)msg.buf;
cc.encodeN = (short)msg.userID;
}
printf("[系统提示] 个人密码策略更新成功!\n");
}
// 文件传输请求
if(msg.msgType==12)
{
MESSAGE msgSend;
memcpy((char *)&msgSend,(char *)&msg,sizeof(MESSAGE));
cout<<"有ID为"<<msg.userID[1]<<"的用户"
<<"向您传送文件,是否接受?(Y/N)"<<endl;
char c=getchar();
if(c=='N') // 拒绝接受
{
msgSend.msgType = 7;
}
else // 接受请求
{
FILETRANS ft;
ft.destID=msg.userID[0];
ft.srcID=msg.userID[1];
strcpy(ft.serverIP ,cc.m_serverIP);
ft.serverPort = cc.m_servPort;
memcpy(ft.fileName,msg.buf,strlen((char *)msg.buf));
memcpy( ft.buf, msg.buf, 1950 );
}
msgSend.userID[0]=msgSend.userID[1];
msgSend.userID[1]=msgSend.userID[0];
send(cc.m_servSocket,(char *)&msgSend,sizeof(MESSAGE),0); // 将应答发送给服务器
}
}
}
}
}
服务器发来的消息类型为12即 msgType=12时,就有问题了。
请指教。 |
|