Browse Source

first beta

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

+ 194
- 28
libptsocket/ptsocket.cpp View File

@@ -3,55 +3,221 @@
3 3
 
4 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 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 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 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 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,29 +4,67 @@
4 4
 #include "libptsocket_global.h"
5 5
 #include <QObject>
6 6
 #include <QTcpSocket>
7
+#include <QHostAddress>
7 8
 #include <QTimer>
8 9
 
9 10
 class LIBPTSOCKETSHARED_EXPORT PTSocket : public QTcpSocket
10 11
 {
11 12
 	Q_OBJECT
12 13
 public:
14
+    enum State
15
+    {
16
+        Disconnected,
17
+        HostLookUp,
18
+        Connecting,
19
+        Connected,
20
+        Handshaked,
21
+        Disconnecting,
22
+        Error
23
+    };
13 24
 	PTSocket(QObject* p);
14 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 38
 public slots:
19
-	void handshake();
20 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 44
 private slots:
45
+    void m_ping();
23 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 55
 private:
27
-	bool m_hasHandshaked;
28 56
 	QTimer m_timeoutTimer;
57
+    QTimer m_pingTimer;
29 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 70
 #endif // PTSOCKET_H

+ 1
- 0
tests/main.cpp View File

@@ -6,6 +6,7 @@ int main(int argc, char *argv[])
6 6
 {
7 7
 	QCoreApplication a(argc, argv);
8 8
 	Test t;
9
+    t.testIntConvert();
9 10
 	t.testListen(6950);
10 11
 	t.testNewConnection();
11 12
 	

+ 24
- 3
tests/test.cpp View File

@@ -4,7 +4,16 @@ Test::Test(QObject *parent) : QObject(parent)
4 4
 {
5 5
 	m_serv = new PTServer(this);
6 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 19
 void Test::testListen(quint16 p)
@@ -16,8 +25,9 @@ void Test::testNewConnection()
16 25
 {
17 26
 	ASSERT_LISTEN;
18 27
 	PTSocket* sock = new PTSocket(this);
28
+    connect(sock, SIGNAL(stateChanged(PTSocket::State)), this, SLOT(m_clientStateChanged(PTSocket::State)));
19 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 33
 void Test::m_newConnection()
@@ -27,5 +37,16 @@ void Test::m_newConnection()
27 37
 
28 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,12 +17,14 @@ public:
17 17
 signals:
18 18
 	
19 19
 public slots:
20
+    void testIntConvert();
20 21
 	void testListen(quint16 p);
21 22
 	void testNewConnection();
22 23
 
23 24
 private slots:
24 25
 	void m_newConnection();
25 26
 	void m_newClient(PTSocket* s);
27
+    void m_clientStateChanged(PTSocket::State s);
26 28
 
27 29
 private:
28 30
 	PTServer* m_serv;

Loading…
Cancel
Save