Socket的select制作多客户端传输(Qt)
界面用的Qt做的,制作的是一个小工具,实在是没时间,代码只是初步代码,很多Bug,估计还不能完美运行起来了。开始打算增加个内网穿透模块的,一来找不到服务器,二来工作上上最近换新框架,真的抽不出时间来,每天下班都比较累,想听下音乐放松下就洗洗睡了,各位不要见笑。
下面上代码。初步模型呢,画了个图,方便理解,都是小东西,select是过时的东西了,并不适合真正的项目了。
代码如下:
Server:
Server.h class ServerInit { public: ServerInit(void); ~ServerInit(void); void Init(); void CheckPackType(SOCKET *_socket); void AddFileinfo(DataInfo _datainfo,SOCKET *_sock); void SendInfo(SOCKET _sock,ServerInit *pServer); void ClientRegister(DataInfo *_pdata,SOCKET *_sock); FD_SET * GetFD(){return &m_fd;} SOCKET* GetSocket(){return &m_ServerSock;} std::map<char*,ServerInfo>* GetMap(){return &m_ClientData;} std::map<SOCKET,sockaddr_in> m_clientIP; private: SOCKET m_ServerSock; WSADATA m_ServerData; SOCKADDR_IN m_ServerADDR; SOCKET m_acceptClient; HANDLE m_handle; DWORD m_ThreadID; FD_SET m_fd; std::map<char*,ServerInfo>m_ClientData; };
Server.cpp #include "stdafx.h" #include "ServerInit.h" timeval g_timeout = {1,0}; //2s轮询 ServerInit::ServerInit(void) { #ifdef WIN32 int errorValue = WSAStartup(MAKEWORD(2,2),&m_ServerData); if (errorValue != NO_ERROR) { printf("Init Error,Get Version Error"); return; } if(LOBYTE(m_ServerData.wVersion)!=2 || HIBYTE(m_ServerData.wVersion)!=2) { printf("Error,网络初始化错误"); return ; } #endif m_ServerSock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(m_ServerSock == INVALID_SOCKET) { return; } m_ServerADDR.sin_family = AF_INET; m_ServerADDR.sin_addr.S_un.S_addr =INADDR_ANY; m_ServerADDR.sin_port = htons(SERVER_PORT); if(bind(m_ServerSock,(sockaddr*)&m_ServerADDR,sizeof(m_ServerADDR))<0) { return ; } listen(m_ServerSock,20); FD_ZERO(&m_fd); FD_SET(m_ServerSock,&m_fd); } ServerInit::~ServerInit(void) { } //检测包的类型 void ServerInit::CheckPackType(SOCKET *_socket) { DataInfo *buff = new DataInfo; recv(*_socket,(char*)buff,g_Packlength,NULL); switch (buff->id) { case IsRegister: ClientRegister(buff,_socket);break; case SEARCHDATA: SendInfo(_sock,pServer);break; case sendFileInfo: AddFileinfo(pdata,_sock); default: printf("错误的数据类型== %d",pdata.id); break; } } void ServerInit::ClientRegister(DataInfo *_pdata,SOCKET *_sock) { DataInfo RegisterInfo; std::map<SOCKET,sockaddr_in>::iterator _clientinfo = m_clientIP.find(*_sock); assert(_clientinfo != m_clientIP.end()); char* clientIP = inet_ntoa(_clientinfo->second.sin_addr); std::map<char*,ServerInfo>::iterator _iter = m_ClientData.find(clientIP); if (_iter == m_ClientData.end()) { printf("新的用户,%s",clientIP); RegisterInfo.id = UnKnowClient; send(*_sock,(char*)&RegisterInfo,sizeof(DataInfo),NULL); } else { RegisterInfo.id = KnowClient; send(*_sock,(char*)&RegisterInfo,sizeof(DataInfo),NULL); } } void ServerInit::SendInfo(SOCKET _sock,ServerInit *pServer) { std::map<char*,ServerInfo>::iterator _iter = pServer->m_ClientData.begin(); DataInfo _datainfo; for (;_iter != pServer->m_ClientData.end();_iter++) { auto _piter = _iter->second.m_info.begin(); for (;_piter != _iter->second.m_info.end();_piter++ ) { _datainfo = *_piter; send(_sock,(char*)&_datainfo,sizeof(DataInfo),NULL); _datainfo.Reset(); } } } void ServerInit::AddFileinfo(DataInfo _datainfo,SOCKET *_sock) { ServerInfo _Sinfo; std::map<SOCKET,sockaddr_in>::iterator itet = m_clientIP.find(*_sock); if (itet == m_clientIP.end()) { assert(false); } _Sinfo.ip = inet_ntoa(itet->second.sin_addr); _Sinfo.port = ntohs(itet->second.sin_port); _Sinfo.m_info.push_back(_datainfo); m_ClientData.insert(std::make_pair(_Sinfo.ip,_Sinfo)); }
main: int g_state; static void ThreadNew(LPVOID lparam) { ServerInit *pData =(ServerInit*)&lparam; sockaddr_in clientinfo; int len = sizeof(sockaddr_in); SOCKET NewClient = accept(*pData->GetSocket(),(sockaddr*)&clientinfo,&len); FD_SET(NewClient,pData->GetFD()); pData->m_clientIP.insert(std::make_pair(NewClient,clientinfo)); _endthread(); } int _tmain(int argc, _TCHAR* argv[]) { ServerInit app; while(true) { FD_SET fd_read = *app.GetFD(); g_state =select(*app.GetSocket()+1,&fd_read,NULL,NULL,NULL); if(g_state > 0) { for (int i = 0; i<app.GetFD()->fd_count;i++) { if (FD_ISSET(app.GetFD()->fd_array[i],&fd_read)) { if (app.GetFD()->fd_array[i] == *app.GetSocket()) { _beginthread(ThreadNew,NULL,(void*)&app); } else { app.CheckPackType((&)app.GetFD()->fd_array[i]); } } } } if (g_state == -1) { int erron = WSAGetLastError(); return -1; } } return 0; }
Client:
client.h
class SockGUIThread : public QMainWindow
{
Q_OBJECT
public:
SockGUIThread(QWidget *parent = 0);
~SockGUIThread();
int InitClient();
int Register();
public slots:
void Search();
private:
Ui::SockGUIThreadClass ui;
SOCKET m_sock;
WSADATA m_data;
int m_errorValue;
SOCKADDR_IN addclient;
char Type[1]; //请求搜索的类型
DataInfo m_recvinfo;
};
client.cpp
SockGUIThread::SockGUIThread(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.m_Search->setEnabled(false);
ui.m_progressBar->setMaximum(100);
ui.m_progressBar->setMinimum(0);
QObject::connect(ui.m_Search,SIGNAL(clicked()),this,SLOT(Search()));
QObject:;connect(ui.m_close,SIGNAL(clicked()),this,SLOT(close()));
Type[0]=1;
if ( InitClient() < 0 )
{
QMessageBox::about(this,"Error","初始化失败,请尝试用管理员权限运行此程序");
closesocket(m_sock);
WSACleanup();
// close();
}
}
SockGUIThread::~SockGUIThread()
{
closesocket(m_sock);
WSACleanup();
}
//第一次安装客户端,提交客户端文件信息
int SockGUIThread::InitClient()
{
m_errorValue = WSAStartup(MAKEWORD(2,2),&m_data);
if (m_errorValue != NO_ERROR)
{
QMessageBox::about(this,"Error","初始化网络错误13001");
return -1;
}
if(LOBYTE(m_data.wVersion)!=2 || HIBYTE(m_data.wVersion)!=2)
{
QMessageBox::about(this,"Error","网络初始化错误13003");
return -1;
}
m_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(m_sock == INVALID_SOCKET)
{
QMessageBox::about(this,"Error","初始化网络出错13002");
return -1;
}
addclient.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
addclient.sin_family = AF_INET;
addclient.sin_port = htons(SERVER_PORT);
if (::connect(m_sock,(LPSOCKADDR)&addclient,sizeof(addclient)) < 0 )
{
QMessageBox::about(this,"Error","连接到服务器失败 初始化");
return -1;
}
DataInfo req;
req.id = IsRegister;
send(m_sock,(char*)&req,g_Packlength("test"),0);
req.Reset();
recv(m_sock,(char*)&req,g_Packlength("test"),0);
if(req.id == UnKnowClient)
{
Register();
}
if(req.id == KnowClient)
{
ui.m_Search->setEnabled(true);
}
return 1;
}
int SockGUIThread::Register()
{
DataInfo req;
QString CurPath;
QDir dir;
CurPath = dir.currentPath();
QStringList _StringList;
_StringList <<QString("*.jpeg")<<QString("*.png")<<QString("*.jpg")<<QString("*.bmp")<<QString("*.rmvb")<<QString("*.avi")<<QString("*.mp4");
dir.setFilter(QDir::Files | QDir::NoSymLinks);
dir.setNameFilters(_StringList);
int fileCount = dir.count();
if(dir.count() == 0)
{
return EmptyFileter;
}
CurPath = dir.currentPath();
QChar _char = QChar('\\');
QStringList filelist;
for (int i=0;i<dir.count();i++)
{
QString file_name = dir[i];
filelist.append(dir.currentPath() + _char + file_name);
}
_StringList.clear();
_StringList<<"Name"<<"Size";
ui.m_tableWidget->setColumnCount(2);
// ui.m_tableWidget->setRowCount(filelist.count());
FileInfo _info;
for (int i=0;i < filelist.count();i++)
{
/* ui.m_tableWidget->setItem(i,0,new QTableWidgetItem(filelist[i]));*/
QFile _file(filelist[i]);
req.id = sendFileInfo;
req.filesize = _file.size();
req.pName =(char*)&filelist[i];
send(m_sock,(char*)&req,g_Packlength(req.pName),NULL);
req.Reset();
/* ui.m_tableWidget->setItem(i,1,new QTableWidgetItem(QString::number((float)_file.size()/1000)+"kb"));*/
}
ui.m_Search->setEnabled(true);
return 1;
}
void SockGUIThread::Search()
{
DataInfo m_recvinfo;
m_recvinfo.Reset();
m_recvinfo.id =SEARCHDATA;
send(m_sock,(char *)&m_recvinfo,g_Packlength(m_recvinfo.pName),0);
m_recvinfo.Reset();
int GetLen = recv(m_sock,(char*)&m_recvinfo,4096,0);
int _Count = ui.m_tableWidget->rowCount();
ui.m_tableWidget->setItem(_Count+1,0,new QTableWidgetItem(m_recvinfo.pName));
ui.m_tableWidget->setItem(_Count+1,1,new QTableWidgetItem(QString::number((float)m_recvinfo.filesize/(10*6))+"Mb"));
}
DataInfo.h #include <list> #include <map> #include <memory.h> #define MAX_ARRAY 1024 #define SERVER_IP "127.0.0.1" #define SERVER_PORT 5656 #define KnowClient 1 #define UnKnowClient 3 #define IsRegister 2 #define RequestFileInfo 10 #define sendFileInfo 11 #define EmptyFileter 20 #define SEND_ERROR -5 #define SEARCHDATA 30 struct FileInfo { long filesize; char *pName; }; //连接服务端数据类型 struct DataInfo { int id; //id 请求类型 long filesize; char *pName; void Reset() { id =NULL; filesize =NULL; pName =NULL; } }; struct ServerInfo { char *ip; int port; std::list<DataInfo> m_info; }; #define g_Packlength(str) (sizeof(DataInfo)+strlen(str))