本人是新手小白一枚,作为练手,我试着写了一篇实现两个客户端实时交换数据的服务器。
由于写的很简单,所以没分文件,全在一个main里面了。
在定义TCPsocket类的时候,我想用到信号和槽,于是在类的定义时加了Q_OBJECT。编译通过,但是链接马上就出现了“不能识别外部符号”之类的奇奇怪怪的错误,把Q_OBJECT去掉之后,又可以运行了。
天啊~~搞到我纠结无比,烦恼无比,求大家帮忙帮忙!!!
#include <QtGui>
#include <QtCore/QCoreApplication>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThread>
#include <QObject>
#include<vector>
int times = 0 ;
int max_score = 0 ;
int receive_count;
int connect_count;
int m_fd ;
int score;
int start_mark = 0 ;
int start_time = 0 ;
std::vector<int> ID_mark ;
//////////////////////////////////////////////////////////
class TcpSocket : public QTcpSocket
{
//void updateClientss( QString,QString ); ///////无法解析?无法解析?
Q_OBJECT
signals:
void enddd();
private:
QReadWriteLock lock;
// void end( ) ;
public :
void dataReceived() ; /////在这儿被引用,对啊?
void updateClients( QString,QString );
}; //socket 的类,主要是要用到他的信号跟槽
////////////////////////////////////////////////////////
QList< TcpSocket *> SocketList ;
class ServerThread:public QThread
{
public:
ServerThread(int fd, QObject *parent);
void run();
//void retn() ;
private:
//new add
QReadWriteLock lock;
};
ServerThread::ServerThread(int fd, QObject *parent ):QThread(parent)
{
m_fd = fd;
int k = m_fd ;
ID_mark.push_back( k ) ;
lock.lockForWrite();
lock.unlock();
}
void TcpSocket::dataReceived( ) //收到客户端的信息
{
QDataStream in(this);
in.setVersion(QDataStream::Qt_4_3);
QString flag ;
QString data ;
in >> flag ;
// 首先是开始游戏的判断。
in >> data ;
emit enddd( ); //传送到判断 + 传送函数 //////就是这儿说无法解析,一旦发送就无法解析,肿马了?!到底是肿马了?!
}
void TcpSocket::updateClients( QString flag , QString data ) //收到客户端的信息进行判断
{
TcpSocket* socket = this ;
if( flag == "start_the_game" )
{
QByteArray block_3;
QDataStream out_3(&block_3, QIODevice::WriteOnly);
out_3.setVersion(QDataStream::Qt_4_3);
lock.lockForWrite();
++(start_mark);
qDebug("I'm Here11111111");
forever
{
if(start_mark==2)
{
QString start_game(tr("start_game")) ;
out_3<<start_game ;
out_3<<start_game ;
start_time ++ ;
lock.unlock();
break ;
}
}
qDebug("I'm Here222222222222");
out_3.device()->seek(0);
socket->write(block_3);
if ( start_time ==2 )
{
start_time = 0 ;
start_mark = 0 ;
}
//out<<secret;
//*max_score=0;
} //if
qDebug("I'm H333333333333");
if( flag == tr("end_the_game") ) //关键字: 游戏结束
{
bool ok(false); //QString转成int
score= QString(data).toInt(&ok);
lock.lockForWrite();
max_score=max_score>score? max_score:score;
lock.unlock();
/*
等待数据写完,不加这个函数,接收方总是只能接收到空数据,长度为0
*/
//qDebug("I'v send the data");
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_3);
lock.lockForWrite();
++(connect_count); //加1在这儿进行!!!!!利用上锁,先让socket2先读到connect_count,不然socket1会先抢到 == 2 的信号退出清0,socket2死循环
forever
{
if(connect_count==2)
{
if(score==max_score)
out<<tr("You win");
else if(score<max_score)
out<<tr("Sorry, you lose");
times ++ ;
lock.unlock();
break;
}
}
if( times == 2)
{
max_score=0;
connect_count=0; //清零在最后!!先退出循环即可
times = 0 ;
}
out.device()->seek(0);
socket->write(block);
} //end_the_game
if( flag == "translate_data" ) //关键字,下标发生改变(客户端自加对方分数1)
{ qDebug("I'm Here3translate_data333");
QByteArray block_2;
QDataStream out_2(&block_2, QIODevice::WriteOnly);
out_2.setVersion(QDataStream::Qt_4_3);
QString mes("location_imformation") ;
//socket->waitForReadyRead(-1); //接
// int location ;
// in >> location ;
//QString str_location=QString::number( location );
for(int i=0;i<SocketList.count();i++) /*这里给对方送去改变的值*/
{
QTcpSocket *item= SocketList.at(i);
if(ID_mark != m_fd)
{
out_2 << mes <<data ;
item->write(block_2);
out_2.device()->seek(0);
}
qDebug("I'm He3");
}
} //the location information
} //发送到客户端的函数
void ServerThread::run()
{
/* 在这个进程里,读取数据,写出数据 */
qDebug("I'm Here");
TcpSocket socket_np ;
TcpSocket *socket = &socket_np;
//*socket = socket_np.retn() ;
qDebug("I'm Here11111111");
/* 根据手册要这么使用 */
if (! (socket_np.setSocketDescriptor( m_fd )) )
{
qDebug("Socket error!");
return;
}
qDebug("I'm Here11111111");
SocketList.append(socket) ;
connect(socket, SIGNAL(readyRead()),socket, SLOT(dataReceived( ))); //没有这个槽?
//connect(socket,SIGNAL(updateClientss(QString,QString,TcpSocket*)),socket,SLOT(updateClients(QString,QString)));
}
class Server : public QTcpServer
{
public:
Server();
private:
/* 当产生一个新的连接的时候,会调用这个函数
所以可以在我们定义的类中,把它改写覆盖掉,
继承来的父类,这个函数是虚函数
*/
void incomingConnection(int sockDescriptor);
};
Server::Server():QTcpServer()
{
}
void Server::incomingConnection(int sockDescriptor)
{
/* 在这里面开辟一个线程来处理连接 */
ServerThread *thread = new ServerThread(sockDescriptor, this);
/*connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); */
thread->start();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Server server;
/* 监听了所有网络接口,6178端口 */
if ( !server.listen(QHostAddress::Any, 6178)) {
qCritical("Cannot listen to port 6178.");
server.close();
return 1;
}
QPushButton quitButton(QObject::tr("&Quit"));
quitButton.setWindowTitle(QObject::tr("Trip Server"));
QObject::connect(&quitButton, SIGNAL(clicked()),
&a, SLOT(quit()));
quitButton.show();
return a.exec();
}