-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsocket.cpp
356 lines (331 loc) · 10.3 KB
/
socket.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
#include "socket.h"
#include<QDebug>
#include<QNetworkInterface>
#include<QByteArray>
#include<QDataStream>
#include<QNetworkReply>
#include<QJsonParseError>
#include<QJsonDocument>
Socket::Socket()
{
this->friendsModel=new FriendsModel();
this->udpSocket=NULL;
//tcp
bytesWrriten=0;
payloadSize=4*1024;
//robot
robot=new Robot();
connect(robot->getManager(), SIGNAL(finished(QNetworkReply *)),
this, SLOT(replyFinished(QNetworkReply *)));
}
FriendsModel *Socket::getFriendsModel() const
{
return friendsModel;
}
ChatRecordsModel *Socket::getChatModel()
{
bool b_contain=map.contains(this->currentFriend);
if(b_contain){
return map[this->currentFriend];
}
else{
ChatRecordsModel* ptr=new ChatRecordsModel();
map[this->currentFriend]=ptr;
return ptr;
}
}
void Socket::setCurrentFriend(const QString &value)
{
currentFriend = value;
}
void Socket::initalizeNetwork()
{
QList<QHostAddress> list=QNetworkInterface::allAddresses();
foreach (QHostAddress addr, list) {
if(addr.protocol()==QAbstractSocket::IPv4Protocol){
this->ipv4=addr.toString();
}
}
udpPort=44332;
udpSocket=new QUdpSocket(this);
bool success=udpSocket->bind(QHostAddress::AnyIPv4, udpPort,QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint);
qDebug()<<"BIND:"<<success;
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(handleComingDatagrams()));
}
void Socket::sendMsg(int type,QString address,QString friendName,QString content)
{
QHostAddress targetAddress;
if(address=="broadcast"){
targetAddress=QHostAddress::Broadcast;
}
else{
targetAddress=QHostAddress(address);
}
QByteArray data;//to send
QDataStream out(&data,QIODevice::WriteOnly);
out<<type<<nickName<<ipv4;// Type MyName MyIP
switch (type) {
case HELLO:// HELLO MyName MyIP
udpSocket->writeDatagram(data,data.length(),targetAddress,udpPort);
break;
case EXIT:
udpSocket->writeDatagram(data,data.length(),targetAddress,udpPort);
break;
case SAY:
// SAY MyName MyIp FriendName content
out<<friendName<<content;
udpSocket->writeDatagram(data,data.length(),targetAddress,udpPort);
break;
case FILECOME:// FILECOME MyName MyIP FriendName FileName
out<<friendName<<content;
udpSocket->writeDatagram(data,data.length(),targetAddress,udpPort);
break;
case FILEREFUSE:
udpSocket->writeDatagram(data,data.length(),targetAddress,udpPort);
break;
case ROBOT:
// qDebug()<<"send to robot";
sendToRobot(content);
break;
default:
qDebug()<<"wrong proctol";
break;
}
}
void Socket::initalizeTcp()
{
tcpPort=34234;
bytesToWrite=0;
this->tcpServer=new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(sendFile()));
connect(tcpServer,SIGNAL(acceptError(QAbstractSocket::SocketError)),
this,SLOT(printMsg(QAbstractSocket::SocketError)));
if(!tcpServer->listen(QHostAddress::Any,tcpPort)){
qDebug()<<"TCP LISTEN ERROR";
return;
}
else {
qDebug()<<"TCP listening...";
}
}
void Socket::setFileName(const QString &value)
{
fileName = value;
if(!fileName.isEmpty()){
theFileName=fileName.right(fileName.size()-fileName.lastIndexOf('/')-1);
}
qDebug()<<theFileName;
}
void Socket::acceptAndConnect(QString friendIPv4)
{
bytesReceived=0;
fileNameSize=0;
totalBytes=0;
tcpPort=34234;
this->r_blockSize=0;
tcpSocketRec=new QTcpSocket(this);
connect(tcpSocketRec,SIGNAL(readyRead()),this,SLOT(recFile()));
tcpSocketRec->abort();
tcpSocketRec->connectToHost(QHostAddress(friendIPv4),tcpPort);
// tcpSocketRec->connectToHost(QHostAddress::LocalHost,tcpPort);
}
void Socket::setFullPath(QString dir)
{
this->r_path=dir;
//wait to recived filename
}
void Socket::clearNewMsgCount(int row)
{
this->friendsModel->clearNewMsgCount(row);
}
void Socket::sendToRobot(QString content)
{
this->robot->post(content);
}
void Socket::handleComingDatagrams()
{
while(udpSocket->hasPendingDatagrams()){
QByteArray comingData;//recived
comingData.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(comingData.data(),comingData.size());
QDataStream in(&comingData,QIODevice::ReadOnly);
int msgType;
QString friendName;
QString friendIpv4;
QString chatContent="";
QString targetName="";
FriendItem item;
int index=0;
in>>msgType>>friendName>>friendIpv4;
if(friendName==nickName&&friendIpv4==ipv4){
return;
}
switch (msgType) {
case HELLO:
//must add this condition to avoid endless send Hello
if(!friends.contains(friendName+friendIpv4)){
friendsModel->pushBack(friendIpv4,friendName);
friends.push_back(friendName+friendIpv4);
sendMsg(HELLO,friendIpv4,"all");
}
break;
case EXIT:
if(friends.contains(friendName+friendIpv4)){
int index=friendsModel->getItems().indexOf(FriendItem(friendIpv4,friendName));
emit friendExit(index);
friendsModel->remove(index);
friends.removeOne(friendName+friendIpv4);
}
break;
case SAY:
// FriendName content
in>>targetName;
if(targetName!=nickName){
qDebug()<<targetName<<":NOT ME";
return;
}
in>>chatContent;
if(map.contains(friendName+friendIpv4)){
map[friendName+friendIpv4]->pushBack(chatContent,false);
}
else{
map[friendName+friendIpv4]=new ChatRecordsModel();
map[friendName+friendIpv4]->pushBack(chatContent,false);
}
emit updateChatView();
//to notify newMsgCount
index=friendsModel->getItems().indexOf(FriendItem(friendIpv4,friendName));
friendsModel->addNewMsgCount(index);
break;
case FILECOME:// FriendName FileName
in>>targetName;
if(targetName!=nickName){
qDebug()<<targetName<<":NOT ME";
return;
}
in>>chatContent;
emit fileCome(friendName,friendIpv4,chatContent);
break;
case FILEREFUSE:
emit fileStatus("Refuse");
default:
break;
}
}//while-end
}
void Socket::sendFile()
{
// send file's total size, filename
tcpSocketSend=tcpServer->nextPendingConnection();
connect(tcpSocketSend,SIGNAL(bytesWritten(qint64)),this,SLOT(SendContinueAndUpdateProgressBar(qint64)));
locFile=new QFile(fileName);
if(!locFile->open(QFile::ReadOnly)){
qDebug()<<"file open fail";
return ;
}
totalBytesToSend=locFile->size();
QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_4_7);
sendOut<<qint64(0)<<qint64(0)<<theFileName;
this->totalBytesToSend+=outBlock.size();
sendOut.device()->seek(0);
sendOut<<totalBytesToSend<<qint64(outBlock.size()-sizeof(qint64)*2);
bytesToWrite=totalBytesToSend-tcpSocketSend->write(outBlock);
outBlock.resize(0);
}
void Socket::SendContinueAndUpdateProgressBar(qint64 numBytes)
{
//send file data
bytesWrriten+=(int)numBytes;
if(bytesToWrite>0){
outBlock=locFile->read(qMin(bytesToWrite,payloadSize));
bytesToWrite-=(int)tcpSocketSend->write(outBlock);
outBlock.resize(0);
}
else{
locFile->close();
}
if(bytesWrriten==totalBytesToSend){
locFile->close();
tcpServer->close();
emit fileStatus("Success");
}
emit updateProgressBar(bytesWrriten/totalBytesToSend);
}
void Socket::recFile()
{
//reference
QDataStream in(tcpSocketRec);
in.setVersion(QDataStream::Qt_4_7);
if(bytesReceived <= sizeof(qint64)*2)
{ //如果接收到的数据小于16个字节,那么是刚开始接收数据,我们保存到//来的头文件信息
if((tcpSocketRec->bytesAvailable() >= sizeof(qint64)*2)&& (fileNameSize == 0))
{ //接收数据总大小信息和文件名大小信息
in >> totalBytes >> fileNameSize;
bytesReceived += sizeof(qint64) * 2;
}
if((tcpSocketRec->bytesAvailable() >= fileNameSize)
&& (fileNameSize != 0))
{ //接收文件名,并建立文件
in >> r_fileName;
bytesReceived += fileNameSize;
localFile = new QFile(r_path+'/'+ r_fileName);
if(!localFile->open(QFile::WriteOnly))
{
qDebug() << "open file error!";
return;
}
}
else return;
}
if(bytesReceived < totalBytes)
{ //如果接收的数据小于总数据,那么写入文件
bytesReceived += tcpSocketRec ->bytesAvailable();
inBlock = tcpSocketRec->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
if(bytesReceived == totalBytes)
{ //接收数据完成时
tcpSocketRec->close();
localFile->close();
emit recSuccess();
}
emit updateRecBar(bytesReceived/totalBytes);
}
void Socket::printMsg(QAbstractSocket::SocketError socketError)
{
qDebug()<<socketError;
}
void Socket::replyFinished(QNetworkReply *reply)
{
QByteArray bytes = reply->readAll();
QJsonParseError jsonError;
QJsonDocument doucment = QJsonDocument::fromJson(bytes, &jsonError);
if (jsonError.error != QJsonParseError::NoError) {
qDebug() << QStringLiteral("fail to read json");
return;
}
// 解析Json
QString response;
if (doucment.isObject()) {
QJsonObject obj = doucment.object();
QJsonValue value;
if (obj.contains("text")) {
value = obj.take("text");
if (value.isString()) {
response= value.toString();
}
}
}
map["robot"]->pushBack(response,false);
emit updateChatView();
}
QString Socket::getNickName() const
{
return nickName;
}
void Socket::setNickName(const QString &value)
{
nickName = value;
}