Browse Source

first beta

master
robin 10 years ago
parent
commit
cc12693884
7 changed files with 310 additions and 38 deletions
  1. 39
    3
      libptsocket/ptserver.cpp
  2. 8
    0
      libptsocket/ptserver.h
  3. 194
    28
      libptsocket/ptsocket.cpp
  4. 42
    4
      libptsocket/ptsocket.h
  5. 1
    0
      tests/main.cpp
  6. 24
    3
      tests/test.cpp
  7. 2
    0
      tests/test.h

+ 39
- 3
libptsocket/ptserver.cpp View File

2
 
2
 
3
 PTServer::PTServer(QObject *parent) : QTcpServer(parent)
3
 PTServer::PTServer(QObject *parent) : QTcpServer(parent)
4
 {
4
 {
5
-	connect(this, SIGNAL(newConnection()), this, SLOT(m_newConnection()));
5
+    connect(this, SIGNAL(newConnection()), this, SLOT(m_newConnection()));
6
+}
7
+
8
+PTSocket *PTServer::nextPendingConnection()
9
+{
10
+    PTSocket* sock = 0;
11
+    if(!m_incomings.isEmpty())
12
+        sock = m_incomings.dequeue();
13
+    return sock;
14
+}
15
+
16
+void PTServer::incomingConnection(int handle)
17
+{
18
+    PTSocket* sock = new PTSocket(this);
19
+    sock->setIsServerSide(true);
20
+    sock->setSocketDescriptor(handle);
21
+    m_incomings.enqueue(sock);
6
 }
22
 }
7
 
23
 
8
 void PTServer::m_newConnection()
24
 void PTServer::m_newConnection()
9
 {
25
 {
10
-	PTSocket* client = dynamic_cast<PTSocket*>(nextPendingConnection());
11
-	m_tempClients.append(client);
26
+    PTSocket* client = nextPendingConnection();
27
+    connect(client, SIGNAL(stateChanged(PTSocket::State)), this, SLOT(m_clientStateChanged(PTSocket::State)));
28
+    m_tempClients.append(client);
29
+}
30
+
31
+void PTServer::m_clientStateChanged(PTSocket::State s)
32
+{
33
+    PTSocket* client = qobject_cast<PTSocket*>(sender());
34
+    if(client == 0)
35
+        return;
36
+    if(s == PTSocket::Handshaked)
37
+    {
38
+        m_clients.append(client);
39
+        m_tempClients.removeOne(client);
40
+        emit newClient(client);
41
+    }
42
+    else if(s == PTSocket::Disconnected || s == PTSocket::Error)
43
+    {
44
+        m_tempClients.removeOne(client);
45
+        m_clients.removeOne(client);
46
+        client->deleteLater();
47
+    }
12
 }
48
 }

+ 8
- 0
libptsocket/ptserver.h View File

6
 #include <QTcpServer>
6
 #include <QTcpServer>
7
 #include <QTcpSocket>
7
 #include <QTcpSocket>
8
 #include <QHostAddress>
8
 #include <QHostAddress>
9
+#include <QQueue>
9
 #include "ptsocket.h"
10
 #include "ptsocket.h"
10
 
11
 
11
 class LIBPTSOCKETSHARED_EXPORT PTServer : public QTcpServer
12
 class LIBPTSOCKETSHARED_EXPORT PTServer : public QTcpServer
14
 public:
15
 public:
15
 	explicit PTServer(QObject *parent = 0);
16
 	explicit PTServer(QObject *parent = 0);
16
 
17
 
18
+    virtual PTSocket* nextPendingConnection();
19
+
20
+protected:
21
+    virtual void incomingConnection(int handle);
22
+
17
 signals:
23
 signals:
18
 	void newClient(PTSocket*);
24
 	void newClient(PTSocket*);
19
 	
25
 	
21
 
27
 
22
 private slots:
28
 private slots:
23
 	void m_newConnection();
29
 	void m_newConnection();
30
+    void m_clientStateChanged(PTSocket::State s);
24
 
31
 
25
 private:
32
 private:
26
 	QList<PTSocket*> m_tempClients;
33
 	QList<PTSocket*> m_tempClients;
27
 	QList<PTSocket*> m_clients;
34
 	QList<PTSocket*> m_clients;
35
+    QQueue<PTSocket*> m_incomings;
28
 	
36
 	
29
 };
37
 };
30
 
38
 

+ 194
- 28
libptsocket/ptsocket.cpp View File

3
 
3
 
4
 PTSocket::PTSocket(QObject* p) : QTcpSocket(p)
4
 PTSocket::PTSocket(QObject* p) : QTcpSocket(p)
5
 {
5
 {
6
-	m_hasHandshaked = false;
7
-	m_timeout = 5000;
8
-	connect(&m_timeoutTimer, SIGNAL(timeout()), this, SLOT(m_handshakeError()));
9
-	connect(this, SIGNAL(readyRead()), this, SLOT(m_readyRead()));
6
+    setSocketOption(QAbstractSocket::LowDelayOption, 1);
7
+    m_packetSize = 0;
8
+    setTimeout(5000);
9
+    setPingInterval(1000 * 7);
10
+    m_state = Disconnected;
11
+    m_isServerSide = false;
12
+    connect(&m_timeoutTimer, SIGNAL(timeout()), this, SLOT(m_timedout()));
13
+    connect(&m_pingTimer, SIGNAL(timeout()), this, SLOT(m_ping()));
14
+    connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(m_stateChanged(QAbstractSocket::SocketState)));
15
+    connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(m_socketError(QAbstractSocket::SocketError)));
16
+    connect(this, SIGNAL(readyRead()), this, SLOT(m_readyRead()));
10
 }
17
 }
11
 
18
 
12
 int PTSocket::getTimeout() const
19
 int PTSocket::getTimeout() const
13
 {
20
 {
14
-	return m_timeout;
21
+    return m_timeout;
15
 }
22
 }
16
 
23
 
17
-QByteArray PTSocket::handshakeData() const
24
+int PTSocket::getPingInterval() const
18
 {
25
 {
19
-	return "LibPTSocket";
26
+    return m_pingInterval;
20
 }
27
 }
21
 
28
 
22
-void PTSocket::handshake()
29
+bool PTSocket::isServerSide() const
23
 {
30
 {
24
-	write(handshakeData());
31
+    return m_isServerSide;
32
+}
33
+
34
+QByteArray PTSocket::handshakeData()
35
+{
36
+    return "LibPTSocketv1";
25
 }
37
 }
26
 
38
 
27
 void PTSocket::setTimeout(int t)
39
 void PTSocket::setTimeout(int t)
28
 {
40
 {
29
-	m_timeout = t;
41
+    m_timeout = t;
42
+    if(m_timeoutTimer.isActive())
43
+        m_timeoutTimer.start(m_timeout);
44
+    else
45
+        m_timeoutTimer.setInterval(m_timeout);
46
+}
47
+
48
+void PTSocket::setPingInterval(int p)
49
+{
50
+    m_pingInterval = p;
51
+    if(m_pingTimer.isActive())
52
+        m_pingTimer.start(m_pingInterval);
53
+    else
54
+        m_pingTimer.setInterval(m_pingInterval);
55
+}
56
+
57
+void PTSocket::setIsServerSide(bool s)
58
+{
59
+    m_isServerSide = s;
60
+}
61
+
62
+void PTSocket::send(int pktType, QByteArray data)
63
+{
64
+    send(false, pktType, data);
65
+}
66
+
67
+void PTSocket::send(bool sys, int pktType, QByteArray data)
68
+{
69
+    if(data.isEmpty())
70
+        data = "\0";
71
+    data.prepend(intToByteArray(pktType));
72
+    data.prepend((char)sys);
73
+    data.prepend(intToByteArray(data.size()));
74
+    write(data);
75
+}
76
+
77
+void PTSocket::m_ping()
78
+{
79
+    m_pingTimer.stop();
80
+    if(m_timeoutTimer.isActive())
81
+        return;
82
+    send(true, PingRequest);
83
+    m_timeoutTimer.start();
30
 }
84
 }
31
 
85
 
32
 void PTSocket::m_readyRead()
86
 void PTSocket::m_readyRead()
33
 {
87
 {
34
-	if(m_hasHandshaked)
35
-	{
36
-
37
-	}
38
-	else
39
-	{
40
-		QByteArray handshake = handshakeData();
41
-		if(bytesAvailable() >= handshake.size())
42
-		{
43
-			QByteArray data = read(handshake.size());
44
-			if(data == handshake)
45
-			{
46
-				m_hasHandshaked = true;
47
-			}
48
-			else
49
-				m_handshakeError();
50
-		}
51
-	}
88
+    m_timeoutTimer.stop();
89
+    m_pingTimer.start();
90
+    if(m_state == Handshaked)
91
+    {
92
+        if(m_packetSize == 0)
93
+        {
94
+            if((unsigned)bytesAvailable() >= sizeof(int))
95
+                m_packetSize = byteArrayToInt(read(sizeof(int)));
96
+            else if(bytesAvailable() != 0)
97
+                m_timeoutTimer.start();
98
+        }
99
+        if(m_packetSize != 0)
100
+        {
101
+            if((unsigned)bytesAvailable() >= m_packetSize)
102
+            {
103
+                bool sys = (bool)read(1).at(0);
104
+                QByteArray p = read(sizeof(int));
105
+                int pktType = byteArrayToInt(p);
106
+                QByteArray data = read(m_packetSize - 1 - p.size());
107
+                if(sys)
108
+                {
109
+                    if(pktType == PingRequest)
110
+                        send(true, PingAnswer);
111
+                    //else if(pktType == PingAnswer)
112
+                }
113
+                else
114
+                    emit packetReceived(pktType, data);
115
+                m_packetSize = 0;
116
+                m_readyRead();
117
+            }
118
+            else
119
+                m_timeoutTimer.start();
120
+        }
121
+    }
122
+    else
123
+    {
124
+        QByteArray handshake = handshakeData();
125
+        if(bytesAvailable() >= handshake.size())
126
+        {
127
+            QByteArray data = read(handshake.size());
128
+            if(data == handshake)
129
+            {
130
+                setState(Handshaked);
131
+                m_readyRead();
132
+            }
133
+            else
134
+                m_handshakeError();
135
+        }
136
+        else
137
+            m_timeoutTimer.start();
138
+    }
139
+}
140
+
141
+void PTSocket::m_timedout()
142
+{
143
+    if(m_state == Disconnected)
144
+        return;
145
+    if(m_state == HostLookUp)
146
+        setError("Unable to find the host " + peerName() + " in the time (" + QString::number(m_timeout) + " ms)");
147
+    else if(m_state == Connecting)
148
+        setError("The " + QString(isServerSide()? "client " + peerAddress().toString() : "server " + peerName())  + " didn't answer to the connection request in the time (" + QString::number(m_timeout) + " ms)");
149
+    else if(m_state == Connected)
150
+        setError("The " + QString(isServerSide()? "client " + peerAddress().toString() : "server " + peerName()) + " didn't answer to the handshake in the time (" + QString::number(m_timeout) + " ms)");
151
+    else if(m_state == Handshaked)
152
+        setError("The " + QString(isServerSide()? "client " + peerAddress().toString() : "server " + peerName()) + " timed out (" + QString::number(m_timeout) + " ms)");
153
+    else if(m_state == Disconnecting)
154
+        abort();
52
 }
155
 }
53
 
156
 
54
 void PTSocket::m_handshakeError()
157
 void PTSocket::m_handshakeError()
55
 {
158
 {
159
+    setError("The " + QString(isServerSide()? "client " + peerAddress().toString() : "server " + peerName()) + " didn't answer to the handshake correclty");
160
+}
161
+
162
+void PTSocket::m_stateChanged(QAbstractSocket::SocketState s)
163
+{
164
+    if(s == QAbstractSocket::HostLookupState)
165
+        setState(HostLookUp);
166
+    else if(s == QAbstractSocket::ConnectingState)
167
+        setState(Connecting);
168
+    else if(s == QAbstractSocket::ConnectedState)
169
+    {
170
+        m_packetSize = 0;
171
+        setState(Connected);
172
+        write(handshakeData());
173
+    }
174
+    else if(s == QAbstractSocket::ClosingState)
175
+        setState(Disconnecting);
176
+    m_timeoutTimer.start();
177
+    if(s == QAbstractSocket::UnconnectedState)
178
+    {
179
+        m_timeoutTimer.stop();
180
+        setState(Disconnected);
181
+    }
182
+}
56
 
183
 
184
+void PTSocket::m_socketError(QAbstractSocket::SocketError)
185
+{
186
+    setState(Error);
187
+}
188
+
189
+void PTSocket::setState(PTSocket::State s)
190
+{
191
+    if(s == Handshaked)
192
+        m_pingTimer.start();
193
+    else
194
+        m_pingTimer.stop();
195
+    if(m_state == Error && (s != HostLookUp && s != Connecting))
196
+        return;
197
+    m_state = s;
198
+    emit stateChanged(m_state);
199
+}
200
+
201
+void PTSocket::setError(QString e)
202
+{
203
+    if(m_state == Error)
204
+        return;
205
+    setErrorString(e);
206
+    setState(Error);
207
+}
208
+
209
+QByteArray PTSocket::intToByteArray(int a)
210
+{
211
+    QByteArray data;
212
+    for(unsigned char i = 0; i < sizeof(a); ++i)
213
+        data.append((char)(a >> 8 * i));
214
+    return data;
215
+}
216
+
217
+int PTSocket::byteArrayToInt(QByteArray d)
218
+{
219
+    int a = 0;
220
+    for(unsigned char i = 0; i < d.size(); ++i)
221
+        a |= (unsigned int)((unsigned char)d.at(i) << i * 8);
222
+    return a;
57
 }
223
 }

+ 42
- 4
libptsocket/ptsocket.h View File

4
 #include "libptsocket_global.h"
4
 #include "libptsocket_global.h"
5
 #include <QObject>
5
 #include <QObject>
6
 #include <QTcpSocket>
6
 #include <QTcpSocket>
7
+#include <QHostAddress>
7
 #include <QTimer>
8
 #include <QTimer>
8
 
9
 
9
 class LIBPTSOCKETSHARED_EXPORT PTSocket : public QTcpSocket
10
 class LIBPTSOCKETSHARED_EXPORT PTSocket : public QTcpSocket
10
 {
11
 {
11
 	Q_OBJECT
12
 	Q_OBJECT
12
 public:
13
 public:
14
+    enum State
15
+    {
16
+        Disconnected,
17
+        HostLookUp,
18
+        Connecting,
19
+        Connected,
20
+        Handshaked,
21
+        Disconnecting,
22
+        Error
23
+    };
13
 	PTSocket(QObject* p);
24
 	PTSocket(QObject* p);
14
 	int getTimeout() const;
25
 	int getTimeout() const;
26
+    int getPingInterval() const;
27
+    bool isServerSide() const;
15
 
28
 
16
-	static QByteArray handshakeData() const;
29
+    static QByteArray handshakeData();
30
+
31
+    static QByteArray intToByteArray(int a);
32
+    static int byteArrayToInt(QByteArray d);
33
+
34
+signals:
35
+    void stateChanged(PTSocket::State);
36
+    void packetReceived(int, QByteArray);
17
 
37
 
18
 public slots:
38
 public slots:
19
-	void handshake();
20
 	void setTimeout(int t);
39
 	void setTimeout(int t);
40
+    void setPingInterval(int p);
41
+    void setIsServerSide(bool s);
42
+    void send(int pktType, QByteArray data);
21
 
43
 
22
 private slots:
44
 private slots:
45
+    void m_ping();
23
 	void m_readyRead();
46
 	void m_readyRead();
24
-	void m_handshakeError();
47
+    void m_timedout();
48
+    void m_handshakeError();
49
+    void m_stateChanged(QAbstractSocket::SocketState s);
50
+    void m_socketError(QAbstractSocket::SocketError);
51
+    void setState(State s);
52
+    void setError(QString e);
53
+    void send(bool sys, int pktType, QByteArray data = "");
25
 
54
 
26
 private:
55
 private:
27
-	bool m_hasHandshaked;
28
 	QTimer m_timeoutTimer;
56
 	QTimer m_timeoutTimer;
57
+    QTimer m_pingTimer;
29
 	int m_timeout;
58
 	int m_timeout;
59
+    int m_pingInterval;
60
+    State m_state;
61
+    bool m_isServerSide;
62
+    unsigned int m_packetSize;
63
+    enum PacketType
64
+    {
65
+        PingRequest = 1,
66
+        PingAnswer = 2
67
+    };
30
 };
68
 };
31
 
69
 
32
 #endif // PTSOCKET_H
70
 #endif // PTSOCKET_H

+ 1
- 0
tests/main.cpp View File

6
 {
6
 {
7
 	QCoreApplication a(argc, argv);
7
 	QCoreApplication a(argc, argv);
8
 	Test t;
8
 	Test t;
9
+    t.testIntConvert();
9
 	t.testListen(6950);
10
 	t.testListen(6950);
10
 	t.testNewConnection();
11
 	t.testNewConnection();
11
 	
12
 	

+ 24
- 3
tests/test.cpp View File

4
 {
4
 {
5
 	m_serv = new PTServer(this);
5
 	m_serv = new PTServer(this);
6
 	connect(m_serv, SIGNAL(newConnection()), this, SLOT(m_newConnection()));
6
 	connect(m_serv, SIGNAL(newConnection()), this, SLOT(m_newConnection()));
7
-	connect(m_serv, SIGNAL(newClient(PTSocket*)), this, SLOT(m_newClient(PTSocket*)));
7
+    connect(m_serv, SIGNAL(newClient(PTSocket*)), this, SLOT(m_newClient(PTSocket*)));
8
+}
9
+
10
+void Test::testIntConvert()
11
+{
12
+    QList<int> tests;
13
+    tests << 0 << 1 << 255 << 256 << 65535 << 65536 << -1 << -65535 << -65536 << 123456789 << -123456789;
14
+    for(int i = 0; i < tests.size(); ++i)
15
+        Q_ASSERT(PTSocket::byteArrayToInt(PTSocket::intToByteArray(tests[i])) == tests[i]);
16
+    qDebug()<<"Int convert OK";
8
 }
17
 }
9
 
18
 
10
 void Test::testListen(quint16 p)
19
 void Test::testListen(quint16 p)
16
 {
25
 {
17
 	ASSERT_LISTEN;
26
 	ASSERT_LISTEN;
18
 	PTSocket* sock = new PTSocket(this);
27
 	PTSocket* sock = new PTSocket(this);
28
+    connect(sock, SIGNAL(stateChanged(PTSocket::State)), this, SLOT(m_clientStateChanged(PTSocket::State)));
19
 	m_clients.append(sock);
29
 	m_clients.append(sock);
20
-	sock->connectToHost("127.0.0.1", m_serv->serverPort());
30
+    sock->connectToHost("127.0.0.1", m_serv->serverPort());
21
 }
31
 }
22
 
32
 
23
 void Test::m_newConnection()
33
 void Test::m_newConnection()
27
 
37
 
28
 void Test::m_newClient(PTSocket* s)
38
 void Test::m_newClient(PTSocket* s)
29
 {
39
 {
30
-	qDebug()<<"New client:"<<s->peerAddress()<<s->peerPort();
40
+    connect(s, SIGNAL(stateChanged(PTSocket::State)), this, SLOT(m_clientStateChanged(PTSocket::State)));
41
+    qDebug()<<"New client:"<<s->peerAddress()<<s->peerPort();
42
+}
43
+
44
+void Test::m_clientStateChanged(PTSocket::State s)
45
+{
46
+    PTSocket* sock = qobject_cast<PTSocket*>(sender());
47
+    if(sock == 0)
48
+        return;
49
+    qDebug()<<sock<<sock->isServerSide()<<s;
50
+    if(s == PTSocket::Error)
51
+        qDebug()<<sock->errorString();
31
 }
52
 }

+ 2
- 0
tests/test.h View File

17
 signals:
17
 signals:
18
 	
18
 	
19
 public slots:
19
 public slots:
20
+    void testIntConvert();
20
 	void testListen(quint16 p);
21
 	void testListen(quint16 p);
21
 	void testNewConnection();
22
 	void testNewConnection();
22
 
23
 
23
 private slots:
24
 private slots:
24
 	void m_newConnection();
25
 	void m_newConnection();
25
 	void m_newClient(PTSocket* s);
26
 	void m_newClient(PTSocket* s);
27
+    void m_clientStateChanged(PTSocket::State s);
26
 
28
 
27
 private:
29
 private:
28
 	PTServer* m_serv;
30
 	PTServer* m_serv;

Loading…
Cancel
Save