- 論壇徽章:
- 0
|
有一個(gè)服務(wù)器和兩個(gè)客戶端,客戶端是命令行模式,客戶端之間發(fā)送的消息要經(jīng)過服務(wù)器處理然后再轉(zhuǎn)發(fā),客戶端主線程(main)里用while(1)等待命令輸入,然后根據(jù)相應(yīng)的命令在進(jìn)行操作,另外還建立了一個(gè)子線程CreateThread(NULL,0,ReadSock,NULL,0,NULL);用來接收服務(wù)器發(fā)來的消息, 根據(jù)不同的消息類型做相應(yīng)的響應(yīng),現(xiàn)在有一個(gè)這樣的問題:
在創(chuàng)建的線程里,我要和用戶進(jìn)行交互,(輸入Y或者N),問題就出來了,在子線程里用getchar()進(jìn)行輸入時(shí),總是提示無效的命令格式,也就是說,建立的線程里用戶輸入的字符被當(dāng)作了命令,請(qǐng)問這種問題怎么解決!
把源程序貼上:
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; // 服務(wù)器socket
sockaddr_in m_addrServ; // 保存服務(wù)器信息
// 用戶信息
char m_userName[17]; // 用戶名
LONGLONG m_UserID; // 用戶ID
char m_Password[11]; // 用戶密碼
// 服務(wù)器信息
char m_serverIP[20]; // 服務(wù)器IP
UINT m_servPort; // 服務(wù)器端口
// 密碼策略
char encodeType[6]; // 保存編碼順序,某次編碼不存在時(shí),用'-'表示
short encodeN[6]; // 若為柵欄編碼時(shí),則此數(shù)組中對(duì)應(yīng)位置保存柵欄排數(shù),范圍1~1024;否則,為0
// 客戶端信息
sockaddr_in m_addrClient; // 保存客戶端信息
char m_clientStrIP[20]; // 用于指定客戶端通信所用IP
UINT m_clientPort; // 用于指定客戶端通信所有端口
};
// 通信消息格式
typedef struct Message
{
LONGLONG userID[10]; // 用戶ID信息數(shù)組
BYTE msgType; // 消息類型
BYTE userName[17]; // 用戶名
BYTE buf[1950]; // 登錄、注冊(cè)時(shí)用于保存密碼;聊天時(shí),用于存放聊天信息
}MESSAGE;
typedef struct FileTrans // 文件傳輸
{
char serverIP[20];
UINT serverPort;
LONGLONG destID; // 接收端ID
LONGLONG srcID; // 發(fā)送端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("格式輸入出錯(cuò)!\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("格式輸入出錯(cuò)!\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) // 注冊(cè)
{
if ( argc!=7 && argc!=9 )
{
printf("格式輸入出錯(cuò)!\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格式輸入出錯(cuò)!\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);
// 命令參數(shù)分割
int paramc=0; // 參數(shù)個(gè)數(shù)
char paramv[10][50]; // 參數(shù)內(nèi)容
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++;
}
// 發(fā)送修改密碼消息
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);
}
// 發(fā)送修改加密策略消息
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;
}
// 發(fā)送聊天消息
else if(!strcmp(paramv[0],"send"))
{
// 查找在線用戶列表是否包含目標(biāo)用戶
LONGLONG drtUserID=_atoi64(paramv[1]);
int i;
for( i=0;i<10;i++)
{
if(OLuserID==drtUserID)
break;
}
if(i>=10)
{
printf("該用戶當(dāng)前不在線\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]));
//////////////////////////////////////////////////////////////////////////
// 根據(jù)密碼策略進(jìn)行加密:加密結(jié)果放置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<<"接收用戶當(dāng)前不在線,請(qǐng)重新選擇用戶。"<<endl;
}
// 向服務(wù)器發(fā)送傳文件請(qǐng)求
Message msg;
msg.msgType = 5; // 發(fā)送文件請(qǐng)求消息
msg.userID[0] = _atoi64(paramv[1]); // 接收端ID
msg.userID[1] =cc.m_UserID; // 發(fā)送端ID
memcpy(msg.buf,paramv[2],strlen(paramv[2])); // 文件路徑+文件名
while(send(cc.m_servSocket,(char *)&msg,sizeof(MESSAGE), 0)<sizeof(MESSAGE))
{
cout<<"文件傳輸請(qǐng)求發(fā)送失敗,是否重新發(fā)送請(qǐng)求?(Y/N)"<<endl;
if(getchar()=='N')
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
}
else if(!strcmp(paramv[0],"showme")) // 顯示本機(jī)ID
{
cout<<"本機(jī)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: 發(fā)送消息"<<endl;
cout<<"5 look: 查找在線用戶"<<endl;
cout<<"6 senfile: 傳輸文件"<<endl;
cout<<"7 showme:查看本機(jī)ID"<<endl;
}
// 未定義
else
{
printf("未知的命令類型\n");
}
//////////////////////////////////////////////////////////////////////////
// recv(cc.m_servSocket,(char *)&msg,sizeof(MESSAGE),0); // 當(dāng)有文件傳輸請(qǐng)求時(shí)
//////////////////////////////////////////////////////////////////////////
}
return 0;
}
// 接收服務(wù)器端消息函數(shù)
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);
// 對(duì)接收到你消息分類處理
// ID已被注冊(cè)
if ( msg.msgType == 0 )
{
for(int i=0;i<10;i++)
{
OLuserID=-1;
}
closesocket(cc.m_servSocket);
cc.m_servSocket=NULL;
printf("[系統(tǒng)提示] 該ID已被注冊(cè),請(qǐng)重新注冊(cè)或登錄!\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;
}
// 顯示系統(tǒng)提示信息
if ( msg.msgType == 1 )
printf("[系統(tǒng)提示] 有用戶上線,在線用戶ID列表已更新!\n");
else
printf("[系統(tǒng)提示] 有用戶離線,在線用戶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("[系統(tǒng)提示] 登錄失敗,該用戶ID不存在!\n");
if ( msg.msgType == 4 )
printf("[系統(tǒng)提示] 登錄失敗,登錄密碼錯(cuò)誤!\n");
if ( msg.msgType == 5 )
printf("[警告信息] 該用戶在別處登錄,用戶被迫強(qiáng)制下線\n");
if ( msg.msgType == 7 )
printf("[警告信息] 登錄失。悍⻊(wù)器達(dá)到用戶連接使用上限!\n");
if ( msg.msgType == 8 )
{
printf("[系統(tǒng)提示] 注冊(cè)成功!\n");
printf("[警告信息] 登錄失。悍⻊(wù)器達(dá)到用戶連接使用上限!\n");
}
if ( msg.msgType == 10 )
printf("密碼修改成功,請(qǐng)用新密碼重新登錄\n");
_exit(1);
}
// 聊天消息
if ( msg.msgType == 6 )
{
//////////////////////////////////////////////////////////////////////////
// 根據(jù)個(gè)人密碼策略,對(duì)接收到的數(shù)據(jù)進(jìn)行解密
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("[系統(tǒng)提示] 舊密碼輸入錯(cuò)誤,密碼修改失敗!\n");
}
// 個(gè)人密碼策略設(shè)置更新成功消息
if ( msg.msgType == 11 )
{
for ( int i = 0; i < 6; i++ )
{
cc.encodeType = (char)msg.buf;
cc.encodeN = (short)msg.userID;
}
printf("[系統(tǒng)提示] 個(gè)人密碼策略更新成功!\n");
}
// 文件傳輸請(qǐng)求
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 // 接受請(qǐng)求
{
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); // 將應(yīng)答發(fā)送給服務(wù)器
}
}
}
}
}
服務(wù)器發(fā)來的消息類型為12即 msgType=12時(shí),就有問題了。
請(qǐng)指教。 |
|