├── .gitignore
├── README.md
├── Server
├── TcpServerer.pro
├── eventdispatcher_libev
│ ├── .gitignore
│ ├── .gitmodules
│ ├── .travis.yml
│ ├── eventdispatcher_libev.cpp
│ ├── eventdispatcher_libev.h
│ ├── eventdispatcher_libev.pri
│ ├── eventdispatcher_libev_p.cpp
│ ├── eventdispatcher_libev_p.h
│ ├── readme.txt
│ ├── socknot_p.cpp
│ └── timers_p.cpp
├── main.cpp
├── tcpserver.cpp
├── tcpserver.h
├── tcpsocket.cpp
├── tcpsocket.h
├── threadhandle.cpp
└── threadhandle.h
└── test-client
├── TestClient
├── TestClient.pro
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
├── tcpsocket.cpp
├── tcpsocket.h
├── testsockets.cpp
└── testsockets.h
└── myTcpClient
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
└── myTcpClient.pro
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 |
6 | # Compiled Dynamic libraries
7 | *.so
8 | *.dylib
9 |
10 | # Compiled Static libraries
11 | *.lai
12 | *.la
13 | *.a
14 | /myTcpClient/*.user
15 |
16 | /myQThreadTcpServer/*.user
17 | /myQTcpServer/*.user
18 | *.user
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | QtTcp---Server
2 | ==============
3 |
4 | ### QtTcp多线程Server
5 | > 继承自QTcpServer,多线程处理Qtcpsocket,有两种方式分配线程,固定线程和固定线程处理的连接数。
6 | >
7 | > 代码基于Qt5和C++11,建议win下用mingw版Qt。
8 | >
9 | > 代码中的信号槽用的用Qt5的新语法,以便使用lambda表达式,
10 | >
11 | > 所以有很多lambda表达式的应用。
12 | >
13 | >
14 | >
15 | > [我博客关于此实现的简单说明](http://www.dushibaiyu.com/2013/12/qtcpserver多线程实现.html)
16 |
17 | 注:此为我学习所写,实际应用很多地方没考虑到、、分配的地方应该还有可以优化地方,如果您发现问题请告诉我,有改进最好也告诉我下、、
18 | QLibeventTcpServer为用libevent的时间选择器、、速度好像的确有所增加,但是多线程的话就没有优势了、、
19 | =================
20 | 每个线程有自己的事件循环。
21 | 现在线程分三级,主线程负责监听端口,新建链接,并移动到其他线程中。
22 | socket线程,负责接收和发送数据,一些小处理也可以放在其中。(线程数目可控)
23 | QtConcurrent : 负责处理发送过来的数据。(动态的线程数目。)
24 |
25 |
26 | ===========================
27 | Next:
28 | 重新设计下线程模型,现有的movetothread不是很好。
29 |
30 | ==============
31 | QLibeventTcpServer移到了old分支
32 | 还有原来的测试代码移动到了old分支
--------------------------------------------------------------------------------
/Server/TcpServerer.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2013-09-16T14:24:31
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core network
8 |
9 | TARGET = QThreadTcpServer
10 | TEMPLATE = app
11 |
12 | QT -= gui
13 | CONFIG += console
14 | CONFIG -= app_bundle
15 | CONFIG += C++11
16 |
17 | SOURCES += $$PWD/main.cpp\
18 | $$PWD/tcpserver.cpp \
19 | $$PWD/tcpsocket.cpp \
20 | $$PWD/threadhandle.cpp
21 |
22 | HEADERS += \
23 | $$PWD/tcpserver.h \
24 | $$PWD/tcpsocket.h \
25 | $$PWD/threadhandle.h
26 |
27 | unix:include($$PWD/eventdispatcher_libev/eventdispatcher_libev.pri)
28 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/.gitignore:
--------------------------------------------------------------------------------
1 | *.a
2 | *.o
3 | *.moc
4 | *.prl
5 | *.pro.user
6 | moc_*.cpp
7 | Makefile
8 | Makefile.*
9 | /tests/tst_*
10 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "tests/qt_eventdispatcher_tests"]
2 | path = tests/qt_eventdispatcher_tests
3 | url = git://github.com/sjinks/qt_eventdispatcher_tests.git
4 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 |
3 | compiler:
4 | - gcc
5 | - clang
6 |
7 | branches:
8 | only:
9 | - master
10 |
11 | before_install:
12 | - git submodule update --init --recursive
13 |
14 | install:
15 | - sudo apt-get update -qq
16 | - sudo apt-get install -qq libqt4-dev libqt4-private-dev libev4 libev-dev
17 |
18 | script:
19 | - ./build.sh
20 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/eventdispatcher_libev.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "eventdispatcher_libev.h"
5 | #include "eventdispatcher_libev_p.h"
6 |
7 |
8 | EventDispatcherLibEv::EventDispatcherLibEv(QObject* parent)
9 | : QAbstractEventDispatcher(parent), d_ptr(new EventDispatcherLibEvPrivate(this))
10 | {
11 | }
12 |
13 | EventDispatcherLibEv::~EventDispatcherLibEv(void)
14 | {
15 | }
16 |
17 | bool EventDispatcherLibEv::processEvents(QEventLoop::ProcessEventsFlags flags)
18 | {
19 | Q_D(EventDispatcherLibEv);
20 | return d->processEvents(flags);
21 | }
22 |
23 | bool EventDispatcherLibEv::hasPendingEvents(void)
24 | {
25 | extern uint qGlobalPostedEventsCount();
26 | return qGlobalPostedEventsCount() > 0;
27 | }
28 |
29 | void EventDispatcherLibEv::registerSocketNotifier(QSocketNotifier* notifier)
30 | {
31 | #ifndef QT_NO_DEBUG
32 | if (notifier->socket() < 0) {
33 | qWarning("QSocketNotifier: Internal error: sockfd < 0");
34 | return;
35 | }
36 |
37 | if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
38 | qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
39 | return;
40 | }
41 | #endif
42 |
43 | if (notifier->type() == QSocketNotifier::Exception) {
44 | return;
45 | }
46 |
47 | Q_D(EventDispatcherLibEv);
48 | d->registerSocketNotifier(notifier);
49 | }
50 |
51 | void EventDispatcherLibEv::unregisterSocketNotifier(QSocketNotifier* notifier)
52 | {
53 | #ifndef QT_NO_DEBUG
54 | if (notifier->socket() < 0) {
55 | qWarning("QSocketNotifier: Internal error: sockfd < 0");
56 | return;
57 | }
58 |
59 | if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
60 | qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
61 | return;
62 | }
63 | #endif
64 |
65 | // Short circuit, we do not support QSocketNotifier::Exception
66 | if (notifier->type() == QSocketNotifier::Exception) {
67 | return;
68 | }
69 |
70 | Q_D(EventDispatcherLibEv);
71 | d->unregisterSocketNotifier(notifier);
72 | }
73 |
74 | void EventDispatcherLibEv::registerTimer(int timerId,int interval,
75 | Qt::TimerType timerType,QObject* object)
76 | {
77 | #ifndef QT_NO_DEBUG
78 | if (timerId < 1 || interval < 0 || !object) {
79 | qWarning("%s: invalid arguments", Q_FUNC_INFO);
80 | return;
81 | }
82 |
83 | if (object->thread() != this->thread() && this->thread() != QThread::currentThread()) {
84 | qWarning("%s: timers cannot be started from another thread", Q_FUNC_INFO);
85 | return;
86 | }
87 | #endif
88 |
89 | Qt::TimerType type;
90 | type = timerType;
91 |
92 | Q_D(EventDispatcherLibEv);
93 | if (interval) {
94 | d->registerTimer(timerId, interval, type, object);
95 | }
96 | else {
97 | d->registerZeroTimer(timerId, object);
98 | }
99 | }
100 |
101 | bool EventDispatcherLibEv::unregisterTimer(int timerId)
102 | {
103 | #ifndef QT_NO_DEBUG
104 | if (timerId < 1) {
105 | qWarning("%s: invalid arguments", Q_FUNC_INFO);
106 | return false;
107 | }
108 |
109 | if (this->thread() != QThread::currentThread()) {
110 | qWarning("%s: timers cannot be stopped from another thread", Q_FUNC_INFO);
111 | return false;
112 | }
113 | #endif
114 |
115 | Q_D(EventDispatcherLibEv);
116 | return d->unregisterTimer(timerId);
117 | }
118 |
119 | bool EventDispatcherLibEv::unregisterTimers(QObject* object)
120 | {
121 | #ifndef QT_NO_DEBUG
122 | if (!object) {
123 | qWarning("%s: invalid arguments", Q_FUNC_INFO);
124 | return false;
125 | }
126 |
127 | if (object->thread() != this->thread() && this->thread() != QThread::currentThread()) {
128 | qWarning("%s: timers cannot be stopped from another thread", Q_FUNC_INFO);
129 | return false;
130 | }
131 | #endif
132 |
133 | Q_D(EventDispatcherLibEv);
134 | return d->unregisterTimers(object);
135 | }
136 |
137 | QList EventDispatcherLibEv::registeredTimers(QObject* object) const
138 | {
139 | if (!object) {
140 | qWarning("%s: invalid argument", Q_FUNC_INFO);
141 | return QList();
142 | }
143 |
144 | Q_D(const EventDispatcherLibEv);
145 | return d->registeredTimers(object);
146 | }
147 |
148 | int EventDispatcherLibEv::remainingTime(int timerId)
149 | {
150 | Q_D(const EventDispatcherLibEv);
151 | return d->remainingTime(timerId);
152 | }
153 |
154 | void EventDispatcherLibEv::wakeUp(void)
155 | {
156 | Q_D(EventDispatcherLibEv);
157 |
158 | if (d->m_wakeups.testAndSetAcquire(0, 1))
159 | {
160 | ev_async_send(d->m_base, &d->m_wakeup);
161 | }
162 | }
163 |
164 | void EventDispatcherLibEv::interrupt(void)
165 | {
166 | Q_D(EventDispatcherLibEv);
167 | d->m_interrupt = true;
168 | this->wakeUp();
169 | }
170 |
171 | void EventDispatcherLibEv::flush(void)
172 | {
173 | }
174 |
175 | EventDispatcherLibEv::EventDispatcherLibEv(EventDispatcherLibEvPrivate& dd, QObject* parent)
176 | : QAbstractEventDispatcher(parent), d_ptr(&dd)
177 | {
178 | }
179 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/eventdispatcher_libev.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTDISPATCHER_LIBEV_H
2 | #define EVENTDISPATCHER_LIBEV_H
3 |
4 | #include
5 |
6 | class EventDispatcherLibEvPrivate;
7 |
8 | class EventDispatcherLibEv : public QAbstractEventDispatcher
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit EventDispatcherLibEv(QObject* parent = 0);
13 | virtual ~EventDispatcherLibEv(void);
14 |
15 | virtual bool processEvents(QEventLoop::ProcessEventsFlags flags);
16 | virtual bool hasPendingEvents(void);
17 |
18 | virtual void registerSocketNotifier(QSocketNotifier* notifier);
19 | virtual void unregisterSocketNotifier(QSocketNotifier* notifier);
20 |
21 | virtual void registerTimer(int timerId,int interval,
22 | Qt::TimerType timerType,QObject* object);
23 |
24 | virtual bool unregisterTimer(int timerId);
25 | virtual bool unregisterTimers(QObject* object);
26 | virtual QList registeredTimers(QObject* object) const;
27 | virtual int remainingTime(int timerId);
28 |
29 | virtual void wakeUp(void);
30 | virtual void interrupt(void);
31 | virtual void flush(void);
32 |
33 | protected:
34 | EventDispatcherLibEv(EventDispatcherLibEvPrivate& dd, QObject* parent = 0);
35 |
36 | private:
37 | Q_DISABLE_COPY(EventDispatcherLibEv)
38 | Q_DECLARE_PRIVATE(EventDispatcherLibEv)
39 | QScopedPointer d_ptr;
40 | };
41 |
42 | #endif // EVENTDISPATCHER_LIBEV_H
43 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/eventdispatcher_libev.pri:
--------------------------------------------------------------------------------
1 | HEADERS += \
2 | $$PWD/eventdispatcher_libev.h \
3 | $$PWD/eventdispatcher_libev_p.h
4 | SOURCES += \
5 | $$PWD/eventdispatcher_libev.cpp \
6 | $$PWD/eventdispatcher_libev_p.cpp \
7 | $$PWD/timers_p.cpp \
8 | $$PWD/socknot_p.cpp
9 |
10 | LIBS += -lev
11 |
12 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/eventdispatcher_libev_p.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "eventdispatcher_libev.h"
3 | #include "eventdispatcher_libev_p.h"
4 |
5 | EventDispatcherLibEvPrivate::EventDispatcherLibEvPrivate(EventDispatcherLibEv* const q)
6 | : q_ptr(q), m_interrupt(false), m_base(0), m_wakeup(),m_wakeups(),
7 | m_notifiers(), m_timers(), m_event_list(), m_zero_timers(), m_awaken(false)
8 | {
9 | this->m_base = ev_loop_new(EVFLAG_AUTO);
10 | Q_CHECK_PTR(this->m_base != 0);
11 |
12 | ev_set_userdata(this->m_base, this);
13 |
14 | struct ev_async* tmp = &this->m_wakeup;
15 | ev_async_init(tmp, EventDispatcherLibEvPrivate::wake_up_handler);
16 | ev_async_start(this->m_base, &this->m_wakeup);
17 | }
18 |
19 | EventDispatcherLibEvPrivate::~EventDispatcherLibEvPrivate(void)
20 | {
21 | if (this->m_base) {
22 | ev_async_stop(this->m_base, &this->m_wakeup);
23 |
24 | this->killTimers();
25 | this->killSocketNotifiers();
26 |
27 | ev_loop_destroy(this->m_base);
28 | this->m_base = 0;
29 | }
30 | }
31 |
32 | bool EventDispatcherLibEvPrivate::processEvents(QEventLoop::ProcessEventsFlags flags)
33 | {
34 | Q_Q(EventDispatcherLibEv);
35 |
36 | const bool exclude_notifiers = (flags & QEventLoop::ExcludeSocketNotifiers);
37 | const bool exclude_timers = (flags & QEventLoop::X11ExcludeTimers);
38 |
39 | exclude_notifiers && this->disableSocketNotifiers(true);
40 | exclude_timers && this->disableTimers(true);
41 |
42 | this->m_interrupt = false;
43 | this->m_awaken = false;
44 |
45 | bool result = q->hasPendingEvents();
46 |
47 | Q_EMIT q->awake();
48 | QCoreApplication::sendPostedEvents();
49 |
50 | bool can_wait = !this->m_interrupt && (flags & QEventLoop::WaitForMoreEvents) && !result;
51 | int f = EVLOOP_NONBLOCK;
52 |
53 | if (!this->m_interrupt) {
54 | if (!exclude_timers && this->m_zero_timers.size() > 0) {
55 | result |= this->processZeroTimers();
56 | if (result) {
57 | can_wait = false;
58 | }
59 | }
60 |
61 | if (can_wait) {
62 | Q_EMIT q->aboutToBlock();
63 | f = EVLOOP_ONESHOT;
64 | }
65 |
66 | // Work around a bug when libev returns from ev_loop(loop, EVLOOP_ONESHOT) without processing any events
67 | do {
68 | ev_loop(this->m_base, f);
69 | } while (can_wait && !this->m_awaken && !this->m_event_list.size());
70 |
71 | EventList list;
72 | this->m_event_list.swap(list);
73 |
74 | result |= (list.size() > 0) | this->m_awaken;
75 |
76 | for (int i=0; itype() == QEvent::Timer) {
90 | QTimerEvent* te = static_cast(e.second);
91 | TimerHash::Iterator tit = this->m_timers.find(te->timerId());
92 | if (tit != this->m_timers.end()) {
93 | TimerInfo* info = tit.value();
94 |
95 | struct ev_timer* tmp = &info->ev;
96 | if (!ev_is_pending(tmp) && !ev_is_active(tmp)) { // false in tst_QTimer::restartedTimerFiresTooSoon()
97 | ev_tstamp delta = calculateNextTimeout(info, now);
98 | ev_timer_set(tmp, delta, 0);
99 | ev_timer_start(this->m_base, tmp);
100 | }
101 | }
102 | }
103 |
104 | delete e.second;
105 | }
106 | }
107 |
108 | exclude_notifiers && this->disableSocketNotifiers(false);
109 | exclude_timers && this->disableTimers(false);
110 |
111 | return result;
112 | }
113 |
114 | bool EventDispatcherLibEvPrivate::processZeroTimers(void)
115 | {
116 | bool result = false;
117 | QList ids = this->m_zero_timers.keys();
118 |
119 | for (int i=0; im_zero_timers.find(tid);
122 | if (it != this->m_zero_timers.end()) {
123 | ZeroTimer& data = it.value();
124 | if (data.active) {
125 | data.active = false;
126 |
127 | QTimerEvent event(tid);
128 | QCoreApplication::sendEvent(data.object, &event);
129 | result = true;
130 |
131 | it = this->m_zero_timers.find(tid);
132 | if (it != this->m_zero_timers.end()) {
133 | ZeroTimer& data = it.value();
134 | if (!data.active) {
135 | data.active = true;
136 | }
137 | }
138 | }
139 | }
140 | }
141 |
142 | return result;
143 | }
144 |
145 | void EventDispatcherLibEvPrivate::wake_up_handler(struct ev_loop* loop, struct ev_async* w, int revents)
146 | {
147 | Q_UNUSED(w)
148 | Q_UNUSED(revents)
149 |
150 | EventDispatcherLibEvPrivate* disp = reinterpret_cast(ev_userdata(loop));
151 | disp->m_awaken = true;
152 |
153 | if (!disp->m_wakeups.testAndSetRelease(1, 0)) {
154 | qCritical("%s: internal error, wakeUps.testAndSetRelease(1, 0) failed!", Q_FUNC_INFO);
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/eventdispatcher_libev_p.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTDISPATCHER_LIBEV_P_H
2 | #define EVENTDISPATCHER_LIBEV_P_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | struct TimerInfo {
13 | QObject* object;
14 | struct ev_timer ev;
15 | struct timeval when;
16 | int timerId;
17 | int interval;
18 | Qt::TimerType type;
19 | };
20 |
21 | struct ZeroTimer {
22 | QObject* object;
23 | bool active;
24 | };
25 |
26 | Q_DECLARE_TYPEINFO(TimerInfo, Q_PRIMITIVE_TYPE);
27 | Q_DECLARE_TYPEINFO(ZeroTimer, Q_PRIMITIVE_TYPE);
28 |
29 | ev_tstamp calculateNextTimeout(TimerInfo* info, const struct timeval& now);
30 |
31 | class EventDispatcherLibEv;
32 |
33 | class EventDispatcherLibEvPrivate
34 | {
35 | public:
36 | EventDispatcherLibEvPrivate(EventDispatcherLibEv * const q);
37 | ~EventDispatcherLibEvPrivate(void);
38 | bool processEvents(QEventLoop::ProcessEventsFlags flags);
39 | bool processZeroTimers(void);
40 | void registerSocketNotifier(QSocketNotifier* notifier);
41 | void unregisterSocketNotifier(QSocketNotifier* notifier);
42 | void registerTimer(int timerId, int interval, Qt::TimerType type, QObject* object);
43 | void registerZeroTimer(int timerId, QObject* object);
44 | bool unregisterTimer(int timerId);
45 | bool unregisterTimers(QObject* object);
46 | QList registeredTimers(QObject* object) const;
47 | int remainingTime(int timerId) const;
48 |
49 | typedef QMultiHash SocketNotifierHash;
50 | typedef QHash TimerHash;
51 | typedef QPair, QEvent*> PendingEvent;
52 | typedef QList EventList;
53 | typedef QHash ZeroTimerHash;
54 |
55 | private:
56 | Q_DISABLE_COPY(EventDispatcherLibEvPrivate)
57 | Q_DECLARE_PUBLIC(EventDispatcherLibEv)
58 | EventDispatcherLibEv* const q_ptr;
59 |
60 | bool m_interrupt;
61 | struct ev_loop* m_base;
62 | struct ev_async m_wakeup;
63 | QAtomicInt m_wakeups;
64 | SocketNotifierHash m_notifiers;
65 | TimerHash m_timers;
66 | EventList m_event_list;
67 | ZeroTimerHash m_zero_timers;
68 | bool m_awaken;
69 |
70 | static void socket_notifier_callback(struct ev_loop* loop, struct ev_io* w, int revents);
71 | static void timer_callback(struct ev_loop* loop, struct ev_timer* w, int revents);
72 | static void wake_up_handler(struct ev_loop* loop, struct ev_async* w, int revents);
73 |
74 | bool disableSocketNotifiers(bool disable);
75 | void killSocketNotifiers(void);
76 | bool disableTimers(bool disable);
77 | void killTimers(void);
78 | };
79 |
80 | #endif // EVENTDISPATCHER_LIBEV_P_H
81 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/readme.txt:
--------------------------------------------------------------------------------
1 | 此来自大牛的封装,我根据需求进行了部分改动和精简,源代码库地址:https://github.com/sjinks/qt_eventdispatcher_libev
2 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/socknot_p.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "eventdispatcher_libev_p.h"
5 |
6 | void EventDispatcherLibEvPrivate::registerSocketNotifier(QSocketNotifier* notifier)
7 | {
8 | int sockfd = notifier->socket();
9 | int what;
10 | switch (notifier->type()) {
11 | case QSocketNotifier::Read: what = EV_READ; break;
12 | case QSocketNotifier::Write: what = EV_WRITE; break;
13 | case QSocketNotifier::Exception: /// FIXME
14 | return;
15 |
16 | default:
17 | Q_ASSERT(false);
18 | return;
19 | }
20 |
21 | struct ev_io* data = new struct ev_io;
22 | ev_io_init(data, EventDispatcherLibEvPrivate::socket_notifier_callback, sockfd, what);
23 | data->data = notifier;
24 | ev_io_start(this->m_base, data);
25 |
26 | this->m_notifiers.insertMulti(sockfd, data);
27 | }
28 |
29 | void EventDispatcherLibEvPrivate::unregisterSocketNotifier(QSocketNotifier* notifier)
30 | {
31 | int sockfd = notifier->socket();
32 | SocketNotifierHash::Iterator it = this->m_notifiers.find(sockfd);
33 | while (it != this->m_notifiers.end() && it.key() == sockfd) {
34 | struct ev_io* data = it.value();
35 | if (data->data == notifier) {
36 | ev_io_stop(this->m_base, data);
37 | delete data;
38 | it = this->m_notifiers.erase(it);
39 | }
40 | else {
41 | ++it;
42 | }
43 | }
44 | }
45 |
46 | void EventDispatcherLibEvPrivate::socket_notifier_callback(struct ev_loop* loop, struct ev_io* w, int revents)
47 | {
48 | EventDispatcherLibEvPrivate* disp = reinterpret_cast(ev_userdata(loop));
49 |
50 | SocketNotifierHash::Iterator it = disp->m_notifiers.find(w->fd);
51 | while (it != disp->m_notifiers.end() && it.key() == w->fd) {
52 | struct ev_io* data = it.value();
53 | QSocketNotifier* notifier = reinterpret_cast(data->data);
54 | QSocketNotifier::Type type = notifier->type();
55 |
56 | if ((QSocketNotifier::Read == type && (revents & EV_READ)) || (QSocketNotifier::Write == type && (revents & EV_WRITE))) {
57 | PendingEvent event(notifier, new QEvent(QEvent::SockAct));
58 | disp->m_event_list.append(event);
59 | }
60 |
61 | ++it;
62 | }
63 | }
64 |
65 | bool EventDispatcherLibEvPrivate::disableSocketNotifiers(bool disable)
66 | {
67 | SocketNotifierHash::Iterator it = this->m_notifiers.begin();
68 | while (it != this->m_notifiers.end()) {
69 | struct ev_io* data = it.value();
70 | if (disable) {
71 | ev_io_stop(this->m_base, data);
72 | }
73 | else {
74 | ev_io_start(this->m_base, data);
75 | }
76 |
77 | ++it;
78 | }
79 |
80 | return true;
81 | }
82 |
83 | void EventDispatcherLibEvPrivate::killSocketNotifiers(void)
84 | {
85 | if (!this->m_notifiers.isEmpty()) {
86 | SocketNotifierHash::Iterator it = this->m_notifiers.begin();
87 | while (it != this->m_notifiers.end()) {
88 | struct ev_io* data = it.value();
89 | ev_io_stop(this->m_base, data);
90 | delete data;
91 | ++it;
92 | }
93 |
94 | this->m_notifiers.clear();
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Server/eventdispatcher_libev/timers_p.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "eventdispatcher_libev_p.h"
5 |
6 | #ifdef WIN32
7 | # include "win32_utils.h"
8 | #endif
9 |
10 | namespace {
11 |
12 | static void calculateCoarseTimerTimeout(TimerInfo* info, const struct timeval& now, struct timeval& when)
13 | {
14 | Q_ASSERT(info->interval > 20);
15 | // The coarse timer works like this:
16 | // - interval under 40 ms: round to even
17 | // - between 40 and 99 ms: round to multiple of 4
18 | // - otherwise: try to wake up at a multiple of 25 ms, with a maximum error of 5%
19 | //
20 | // We try to wake up at the following second-fraction, in order of preference:
21 | // 0 ms
22 | // 500 ms
23 | // 250 ms or 750 ms
24 | // 200, 400, 600, 800 ms
25 | // other multiples of 100
26 | // other multiples of 50
27 | // other multiples of 25
28 | //
29 | // The objective is to make most timers wake up at the same time, thereby reducing CPU wakeups.
30 |
31 | int interval = info->interval;
32 | int msec = static_cast(info->when.tv_usec / 1000);
33 | int max_rounding = interval / 20; // 5%
34 | when = info->when;
35 |
36 | if (interval < 100 && (interval % 25) != 0) {
37 | if (interval < 50) {
38 | uint round_up = ((msec % 50) >= 25) ? 1 : 0;
39 | msec = ((msec >> 1) | round_up) << 1;
40 | }
41 | else {
42 | uint round_up = ((msec % 100) >= 50) ? 1 : 0;
43 | msec = ((msec >> 2) | round_up) << 2;
44 | }
45 | }
46 | else {
47 | int min = qMax(0, msec - max_rounding);
48 | int max = qMin(1000, msec + max_rounding);
49 |
50 | bool done = false;
51 |
52 | // take any round-to-the-second timeout
53 | if (min == 0) {
54 | msec = 0;
55 | done = true;
56 | }
57 | else if (max == 1000) {
58 | msec = 1000;
59 | done = true;
60 | }
61 |
62 | if (!done) {
63 | int boundary;
64 |
65 | // if the interval is a multiple of 500 ms and > 5000 ms, always round towards a round-to-the-second
66 | // if the interval is a multiple of 500 ms, round towards the nearest multiple of 500 ms
67 | if ((interval % 500) == 0) {
68 | if (interval >= 5000) {
69 | msec = msec >= 500 ? max : min;
70 | done = true;
71 | }
72 | else {
73 | boundary = 500;
74 | }
75 | }
76 | else if ((interval % 50) == 0) {
77 | // same for multiples of 250, 200, 100, 50
78 | uint tmp = interval / 50;
79 | if ((tmp % 4) == 0) {
80 | boundary = 200;
81 | }
82 | else if ((tmp % 2) == 0) {
83 | boundary = 100;
84 | }
85 | else if ((tmp % 5) == 0) {
86 | boundary = 250;
87 | }
88 | else {
89 | boundary = 50;
90 | }
91 | }
92 | else {
93 | boundary = 25;
94 | }
95 |
96 | if (!done) {
97 | int base = (msec / boundary) * boundary;
98 | int middle = base + boundary / 2;
99 | msec = (msec < middle) ? qMax(base, min) : qMin(base + boundary, max);
100 | }
101 | }
102 | }
103 |
104 | if (msec == 1000) {
105 | ++when.tv_sec;
106 | when.tv_usec = 0;
107 | }
108 | else {
109 | when.tv_usec = msec * 1000;
110 | }
111 |
112 | if (timercmp(&when, &now, <)) {
113 | when.tv_sec += interval / 1000;
114 | when.tv_usec += (interval % 1000) * 1000;
115 | if (when.tv_usec > 999999) {
116 | ++when.tv_sec;
117 | when.tv_usec -= 1000000;
118 | }
119 | }
120 |
121 | Q_ASSERT(timercmp(&now, &when, <=));
122 | }
123 | }
124 |
125 | ev_tstamp calculateNextTimeout(TimerInfo* info, const struct timeval& now)
126 | {
127 | struct timeval tv_interval;
128 | struct timeval when;
129 | tv_interval.tv_sec = info->interval / 1000;
130 | tv_interval.tv_usec = (info->interval % 1000) * 1000;
131 |
132 | if (info->interval) {
133 | qlonglong tnow = (qlonglong(now.tv_sec) * 1000) + (now.tv_usec / 1000);
134 | qlonglong twhen = (qlonglong(info->when.tv_sec) * 1000) + (info->when.tv_usec / 1000);
135 |
136 | if ((info->interval < 1000 && twhen - tnow > 1500) || (info->interval >= 1000 && twhen - tnow > 1.2*info->interval)) {
137 | info->when = now;
138 | }
139 | }
140 |
141 | if (Qt::VeryCoarseTimer == info->type) {
142 | if (info->when.tv_usec >= 500000) {
143 | ++info->when.tv_sec;
144 | }
145 |
146 | info->when.tv_usec = 0;
147 | info->when.tv_sec += info->interval / 1000;
148 | if (info->when.tv_sec <= now.tv_sec) {
149 | info->when.tv_sec = now.tv_sec + info->interval / 1000;
150 | }
151 |
152 | when = info->when;
153 | }
154 | else if (Qt::PreciseTimer == info->type) {
155 | if (info->interval) {
156 | timeradd(&info->when, &tv_interval, &info->when);
157 | if (timercmp(&info->when, &now, <)) {
158 | timeradd(&now, &tv_interval, &info->when);
159 | }
160 |
161 | when = info->when;
162 | }
163 | else {
164 | when = now;
165 | }
166 | }
167 | else {
168 | timeradd(&info->when, &tv_interval, &info->when);
169 | if (timercmp(&info->when, &now, <)) {
170 | timeradd(&now, &tv_interval, &info->when);
171 | }
172 |
173 | calculateCoarseTimerTimeout(info, now, when);
174 | }
175 |
176 | return static_cast(when.tv_sec - now.tv_sec) + static_cast(when.tv_usec - now.tv_usec) * 1.0E-6;
177 | }
178 |
179 |
180 | void EventDispatcherLibEvPrivate::registerTimer(int timerId, int interval, Qt::TimerType type, QObject* object)
181 | {
182 | Q_ASSERT(interval > 0);
183 |
184 | struct timeval now;
185 | gettimeofday(&now, 0);
186 |
187 | TimerInfo* info = new TimerInfo;
188 | info->timerId = timerId;
189 | info->interval = interval;
190 | info->type = type;
191 | info->object = object;
192 | info->when = now; // calculateNextTimeout() will take care of info->when
193 |
194 | if (Qt::CoarseTimer == type) {
195 | if (interval >= 20000) {
196 | info->type = Qt::VeryCoarseTimer;
197 | }
198 | else if (interval <= 20) {
199 | info->type = Qt::PreciseTimer;
200 | }
201 | }
202 |
203 | ev_tstamp delta = calculateNextTimeout(info, now);
204 |
205 | struct ev_timer* tmp = &info->ev;
206 | ev_timer_init(tmp, EventDispatcherLibEvPrivate::timer_callback, delta, 0);
207 | info->ev.data = info;
208 | ev_timer_start(this->m_base, tmp);
209 | this->m_timers.insert(timerId, info);
210 | }
211 |
212 | void EventDispatcherLibEvPrivate::registerZeroTimer(int timerId, QObject* object)
213 | {
214 | ZeroTimer data;
215 | data.object = object;
216 | data.active = true;
217 | this->m_zero_timers.insert(timerId, data);
218 | }
219 |
220 | bool EventDispatcherLibEvPrivate::unregisterTimer(int timerId)
221 | {
222 | TimerHash::Iterator it = this->m_timers.find(timerId);
223 | if (it != this->m_timers.end()) {
224 | TimerInfo* info = it.value();
225 | ev_timer_stop(this->m_base, &info->ev);
226 | delete info;
227 | this->m_timers.erase(it);
228 | return true;
229 | }
230 |
231 | return this->m_zero_timers.remove(timerId) > 0;
232 | }
233 |
234 | bool EventDispatcherLibEvPrivate::unregisterTimers(QObject* object)
235 | {
236 | bool result = false;
237 | TimerHash::Iterator it = this->m_timers.begin();
238 | while (it != this->m_timers.end()) {
239 | TimerInfo* info = it.value();
240 |
241 | if (object == info->object) {
242 | result = true;
243 | ev_timer_stop(this->m_base, &info->ev);
244 | delete info;
245 | it = this->m_timers.erase(it);
246 | }
247 | else {
248 | ++it;
249 | }
250 | }
251 |
252 | ZeroTimerHash::Iterator zit = this->m_zero_timers.begin();
253 | while (zit != this->m_zero_timers.end()) {
254 | ZeroTimer& data = zit.value();
255 | if (object == data.object) {
256 | result = true;
257 | zit = this->m_zero_timers.erase(zit);
258 | }
259 | else {
260 | ++zit;
261 | }
262 | }
263 |
264 | return result;
265 | }
266 |
267 | QList EventDispatcherLibEvPrivate::registeredTimers(QObject* object) const
268 | {
269 | QList res;
270 |
271 | TimerHash::ConstIterator it = this->m_timers.constBegin();
272 | while (it != this->m_timers.constEnd()) {
273 | TimerInfo* info = it.value();
274 | if (object == info->object) {
275 | QAbstractEventDispatcher::TimerInfo ti(it.key(), info->interval, info->type);
276 | res.append(ti);
277 | }
278 |
279 | ++it;
280 | }
281 |
282 | ZeroTimerHash::ConstIterator zit = this->m_zero_timers.constBegin();
283 | while (zit != this->m_zero_timers.constEnd()) {
284 | const ZeroTimer& data = zit.value();
285 | if (object == data.object) {
286 | QAbstractEventDispatcher::TimerInfo ti(it.key(), 0, Qt::PreciseTimer);
287 | res.append(ti);
288 | }
289 |
290 | ++zit;
291 | }
292 |
293 | return res;
294 | }
295 |
296 | int EventDispatcherLibEvPrivate::remainingTime(int timerId) const
297 | {
298 | TimerHash::ConstIterator it = this->m_timers.find(timerId);
299 | if (it != this->m_timers.end()) {
300 | const TimerInfo* info = it.value();
301 |
302 | const struct ev_timer* tmp = &info->ev;
303 | if (ev_is_pending(tmp) || ev_is_active(tmp)) {
304 | ev_tstamp now = ev_now(this->m_base);
305 | ev_tstamp when = static_cast(info->when.tv_sec) + static_cast(info->when.tv_usec) * 1.0E-6;
306 |
307 | if (now > when) {
308 | return 0;
309 | }
310 |
311 | return static_cast((when - now) * 1000);
312 | }
313 | }
314 |
315 | // For zero timers we return -1 as well
316 |
317 | return -1;
318 | }
319 |
320 | void EventDispatcherLibEvPrivate::timer_callback(struct ev_loop* loop, struct ev_timer* w, int revents)
321 | {
322 | Q_UNUSED(revents)
323 |
324 | EventDispatcherLibEvPrivate* self = reinterpret_cast(ev_userdata(loop));
325 | TimerInfo* info = reinterpret_cast(w->data);
326 |
327 | // Timer can be reactivated only after its callback finishes; processEvents() will take care of this
328 | PendingEvent event(info->object, new QTimerEvent(info->timerId));
329 | self->m_event_list.append(event);
330 | }
331 |
332 | bool EventDispatcherLibEvPrivate::disableTimers(bool disable)
333 | {
334 | struct timeval now;
335 | if (!disable) {
336 | gettimeofday(&now, 0);
337 | }
338 |
339 | TimerHash::Iterator it = this->m_timers.begin();
340 | while (it != this->m_timers.end()) {
341 | TimerInfo* info = it.value();
342 | if (disable) {
343 | ev_timer_stop(this->m_base, &info->ev);
344 | }
345 | else {
346 | ev_tstamp delta = calculateNextTimeout(info, now);
347 | struct ev_timer* tmp = &info->ev;
348 | ev_timer_set(tmp, delta, 0);
349 | ev_timer_start(this->m_base, tmp);
350 | }
351 |
352 | ++it;
353 | }
354 |
355 | return true;
356 | }
357 |
358 | void EventDispatcherLibEvPrivate::killTimers(void)
359 | {
360 | if (!this->m_timers.isEmpty()) {
361 | TimerHash::Iterator it = this->m_timers.begin();
362 | while (it != this->m_timers.end()) {
363 | TimerInfo* info = it.value();
364 | ev_timer_stop(this->m_base, &info->ev);
365 | delete info;
366 | ++it;
367 | }
368 |
369 | this->m_timers.clear();
370 | }
371 | }
372 |
--------------------------------------------------------------------------------
/Server/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "tcpserver.h"
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #ifndef Q_OS_WIN
9 | #include "eventdispatcher_libev/eventdispatcher_libev.h"
10 | #endif
11 |
12 | void customMessageHandler(QtMsgType type, const QMessageLogContext &context,const QString & msg)
13 | {
14 | QString txt;
15 | switch (type) {
16 | //调试信息提示
17 | case QtDebugMsg:
18 | // txt = QString("%1: Debug: at:%2,%3 on %4; %5").arg(QTime::currentTime().toString("hh:mm:ss.zzz"))
19 | // .arg(context.file).arg(context.line).arg(context.function).arg(msg);
20 | txt = msg;
21 | break;
22 |
23 | //一般的warning提示
24 | case QtWarningMsg:
25 | txt = QString("%1:Warning: at:%2,%3 on %4; %5").arg(QTime::currentTime().toString("hh:mm:ss.zzz"))
26 | .arg(context.file).arg(context.line).arg(context.function).arg(msg);
27 | break;
28 | //严重错误提示
29 | case QtCriticalMsg:
30 | txt = QString("%1:Critical: at:%2,%3 on %4; %5").arg(QTime::currentTime().toString("hh:mm:ss.zzz"))
31 | .arg(context.file).arg(context.line).arg(context.function).arg(msg);
32 | break;
33 | //致命错误提示
34 | case QtFatalMsg:
35 | txt = QString("%1:Fatal: at:%2,%3 on %4; %5").arg(QTime::currentTime().toString("hh:mm:ss.zzz"))
36 | .arg(context.file).arg(context.line).arg(context.function).arg(msg);
37 | abort();
38 | }
39 | QFile outFile(QString("%1/%2.txt").arg(QDir::currentPath()).arg(QDate::currentDate().toString("yyyy-MM-dd")));
40 | outFile.open(QIODevice::WriteOnly | QIODevice::Append);
41 | QTextStream ts(&outFile);
42 | ts << txt << endl;
43 | }
44 |
45 |
46 | int main(int argc, char *argv[])
47 | {
48 | // qInstallMessageHandler(customMessageHandler);
49 | #ifndef Q_OS_WIN
50 | QCoreApplication::setEventDispatcher(new EventDispatcherLibEv());
51 | #endif
52 | QCoreApplication a(argc, argv);
53 | std::cout << "???" << std::endl;
54 | TcpServer ser;
55 | ser.listen(QHostAddress::Any,6666);
56 |
57 | return a.exec();
58 | }
59 |
--------------------------------------------------------------------------------
/Server/tcpserver.cpp:
--------------------------------------------------------------------------------
1 | #include "tcpserver.h"
2 | #include "threadhandle.h"
3 |
4 | TcpServer::TcpServer(QObject *parent,int numConnections) :
5 | QTcpServer(parent)
6 | {
7 | tcpClient = new QHash;
8 | setMaxPendingConnections(numConnections);
9 | }
10 |
11 | TcpServer::~TcpServer()
12 | {
13 | emit this->sentDisConnect(-1);
14 | delete tcpClient;
15 | }
16 |
17 | void TcpServer::setMaxPendingConnections(int numConnections)
18 | {
19 | this->QTcpServer::setMaxPendingConnections(numConnections);//调用Qtcpsocket函数,设置最大连接数,主要是使maxPendingConnections()依然有效
20 | this->maxConnections = numConnections;
21 | }
22 |
23 | void TcpServer::incomingConnection(qintptr socketDescriptor) //多线程必须在此函数里捕获新连接
24 | {
25 | if (tcpClient->size() > maxPendingConnections())//继承重写此函数后,QTcpServer默认的判断最大连接数失效,自己实现
26 | {
27 | QTcpSocket tcp;
28 | tcp.setSocketDescriptor(socketDescriptor);
29 | tcp.disconnectFromHost();
30 | return;
31 | }
32 | auto th = ThreadHandle::getClass().getThread();
33 | auto tcpTemp = new TcpSocket(socketDescriptor);
34 | QString ip = tcpTemp->peerAddress().toString();
35 | qint16 port = tcpTemp->peerPort();
36 |
37 | connect(tcpTemp,&TcpSocket::sockDisConnect,this,&TcpServer::sockDisConnectSlot);//NOTE:断开连接的处理,从列表移除,并释放断开的Tcpsocket,此槽必须实现,线程管理计数也是考的他
38 | connect(this,&TcpServer::sentDisConnect,tcpTemp,&TcpSocket::disConTcp);//断开信号
39 |
40 | tcpTemp->moveToThread(th);//把tcp类移动到新的线程,从线程管理类中获取
41 | tcpClient->insert(socketDescriptor,tcpTemp);//插入到连接信息中
42 | emit connectClient(socketDescriptor,ip,port);
43 | }
44 |
45 | void TcpServer::sockDisConnectSlot(int handle,const QString & ip, quint16 prot,QThread * th)
46 | {
47 | tcpClient->remove(handle);//连接管理中移除断开连接的socket
48 | ThreadHandle::getClass().removeThread(th); //告诉线程管理类那个线程里的连接断开了
49 | emit sockDisConnect(handle,ip,prot);
50 | }
51 |
52 |
53 | void TcpServer::clear()
54 | {
55 | emit this->sentDisConnect(-1);
56 | ThreadHandle::getClass().clear();
57 | tcpClient->clear();
58 | }
59 |
--------------------------------------------------------------------------------
/Server/tcpserver.h:
--------------------------------------------------------------------------------
1 | #ifndef TCPSERVER_H
2 | #define TCPSERVER_H
3 |
4 | #include
5 | #include
6 | #include "tcpsocket.h"
7 |
8 |
9 | //继承QTCPSERVER以实现多线程TCPscoket的服务器。
10 | //如果socket的信息处理直接处理的话,很多新建的信号和槽是用不到的
11 | class TcpServer : public QTcpServer
12 | {
13 | Q_OBJECT
14 | public:
15 | explicit TcpServer(QObject *parent = 0,int numConnections = 10000);
16 | ~TcpServer();
17 |
18 | void setMaxPendingConnections(int numConnections);//重写设置最大连接数函数
19 | signals:
20 | void connectClient(const int , const QString & ,const quint16 );//发送新用户连接信息
21 | void readData(const int,const QString &, quint16, const QByteArray &);//发送获得用户发过来的数据
22 | void sockDisConnect(int ,QString ,quint16);//断开连接的用户信息
23 | void sentData(const QByteArray &,const int);//向scoket发送消息
24 | void sentDisConnect(int i); //断开特定连接,并释放资源,-1为断开所有。
25 |
26 | public slots:
27 | void clear(); //断开所有连接,线程计数器请0
28 | protected slots:
29 | void sockDisConnectSlot(int handle,const QString & ip, quint16 prot, QThread *th);//断开连接的用户信息
30 |
31 | protected:
32 | void incomingConnection(qintptr socketDescriptor);//覆盖已获取多线程
33 | private:
34 | QHash * tcpClient;//管理连接的map
35 | int maxConnections;
36 |
37 | };
38 |
39 | #endif // TCPSERVER_H
40 |
--------------------------------------------------------------------------------
/Server/tcpsocket.cpp:
--------------------------------------------------------------------------------
1 | #include "tcpsocket.h"
2 | #include
3 | #include
4 | #include
5 |
6 | TcpSocket::TcpSocket(qintptr socketDescriptor, QObject *parent) : //构造函数在主线程执行,lambda在子线程
7 | QTcpSocket(parent),socketID(socketDescriptor)
8 | {
9 | this->setSocketDescriptor(socketDescriptor);
10 | connect(this,&TcpSocket::readyRead,this,&TcpSocket::readData);
11 | dis = connect(this,&TcpSocket::disconnected,
12 | [&](){
13 | qDebug() << "disconnect" ;
14 | emit sockDisConnect(socketID,this->peerAddress().toString(),this->peerPort(),QThread::currentThread());//发送断开连接的用户信息
15 | this->deleteLater();
16 | });
17 | connect(&watcher,&QFutureWatcher::finished,this,&TcpSocket::startNext);
18 | connect(&watcher,&QFutureWatcher::canceled,this,&TcpSocket::startNext);
19 | qDebug() << "new connect" ;
20 | }
21 |
22 | TcpSocket::~TcpSocket()
23 | {
24 | }
25 |
26 |
27 | void TcpSocket::sentData(const QByteArray &data, const int id)
28 | {
29 | if(id == socketID)
30 | {
31 | write(data);
32 | }
33 | }
34 |
35 | void TcpSocket::disConTcp(int i)
36 | {
37 | if (i == socketID)
38 | {
39 | this->disconnectFromHost();
40 | }
41 | else if (i == -1) //-1为全部断开
42 | {
43 | disconnect(dis); //先断开连接的信号槽,防止二次析构
44 | this->disconnectFromHost();
45 | this->deleteLater();
46 | }
47 | }
48 |
49 | void TcpSocket::readData()
50 | {
51 | // datas.append(this->readAll());
52 | auto data = handleData(this->readAll(),this->peerAddress().toString(),this->peerPort());
53 | qDebug() << data;
54 | this->write(data);
55 | // if (!watcher.isRunning())//放到异步线程中处理。
56 | // {
57 | // watcher.setFuture(QtConcurrent::run(this,&TcpSocket::handleData,datas.dequeue(),this->peerAddress().toString(),this->peerPort()));
58 | // }
59 | }
60 |
61 | QByteArray TcpSocket::handleData(QByteArray data, const QString &ip, qint16 port)
62 | {
63 | QTime time;
64 | time.start();
65 |
66 | QElapsedTimer tm;
67 | tm.start();
68 | while(tm.elapsed() < 100)
69 | {}
70 | data = ip.toUtf8() + " " + QByteArray::number(port) + " " + data + " " + QTime::currentTime().toString().toUtf8();
71 | return data;
72 | }
73 |
74 | void TcpSocket::startNext()
75 | {
76 | this->write(watcher.future().result());
77 | if (!datas.isEmpty())
78 | {
79 | watcher.setFuture(QtConcurrent::run(this,&TcpSocket::handleData,datas.dequeue(),this->peerAddress().toString(),this->peerPort()));
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Server/tcpsocket.h:
--------------------------------------------------------------------------------
1 | #ifndef TCPSOCKET_H
2 | #define TCPSOCKET_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 |
12 | class TcpSocket : public QTcpSocket
13 | {
14 | Q_OBJECT
15 | public:
16 | explicit TcpSocket(qintptr socketDescriptor, QObject *parent = 0);
17 | ~TcpSocket();
18 | QByteArray handleData(QByteArray data,const QString & ip, qint16 port);//用来处理数据的函数
19 |
20 | signals:
21 | //void readData(const int,const QString &,const quint16,const QByteArray &);
22 | void sockDisConnect(const int ,const QString &,const quint16, QThread *);//NOTE:断开连接的用户信息,此信号必须发出!线程管理类根据信号计数的
23 | public slots:
24 | void sentData(const QByteArray & ,const int);//发送信号的槽
25 | void disConTcp(int i);
26 |
27 | protected slots:
28 | void readData();//接收数据
29 | void startNext();//处理下一个
30 | protected:
31 | QFutureWatcher watcher;
32 | QQueue datas;
33 | private:
34 | qintptr socketID;
35 | QMetaObject::Connection dis;
36 | };
37 |
38 | #endif // TCPSOCKET_H
39 |
--------------------------------------------------------------------------------
/Server/threadhandle.cpp:
--------------------------------------------------------------------------------
1 | #include "threadhandle.h"
2 | #include "eventdispatcher_libev/eventdispatcher_libev.h"
3 |
4 | ThreadHandle::ThreadHandle()
5 | {
6 | initfist = false;
7 | }
8 |
9 | ThreadHandle::~ThreadHandle() //停止所有线程,并释放资源
10 | {
11 | QThread * tmp;
12 | for (auto it = threadSize.begin(); it != threadSize.end(); ++it)
13 | {
14 | tmp = it.key();
15 | tmp->exit();
16 | tmp->wait(3000);
17 | delete tmp;
18 | }
19 | }
20 |
21 | ThreadHandle & ThreadHandle::getClass()
22 | {
23 | static ThreadHandle th;
24 | return th;
25 | }
26 |
27 | QThread *ThreadHandle::getThread()
28 | {
29 | if (!initfist)
30 | {
31 | initThreadType(THREADSIZE,10);
32 | }
33 | if (type == THREADSIZE)
34 | return findThreadSize();
35 | else
36 | return findHandleSize();
37 | }
38 |
39 | void ThreadHandle::removeThread(QThread * thread)
40 | {
41 | auto t = threadSize.find(thread);
42 | if (t != threadSize.end())
43 | {
44 | t.value() --;
45 | if (type == HANDLESIZE && t.value() == 0 && threadSize.size() > 1)
46 | {
47 | threadSize.remove(thread);
48 | thread->exit();
49 | thread->wait(3000);
50 | delete thread;
51 | }
52 | }
53 | }
54 |
55 | void ThreadHandle::initThreadType(ThreadType type, unsigned int max)
56 | {
57 | if (!initfist)
58 | {
59 | this->type = type;
60 | this->size = max;
61 | if (this->size == 0)
62 | {
63 | if(type == THREADSIZE)
64 | this->size = 10;
65 | else
66 | this->size = 1000;
67 | }
68 |
69 | if (type == THREADSIZE)
70 | initThreadSize();
71 | else
72 | {
73 | QThread * tmp = new QThread;
74 | #ifndef Q_OS_WIN
75 | tmp->setEventDispatcher(new EventDispatcherLibEv());
76 | #endif
77 | threadSize.insert(tmp,0);
78 | tmp->start();
79 | }
80 | }
81 | initfist = true;
82 | }
83 |
84 | void ThreadHandle::initThreadSize() //建立好线程并启动,
85 | {
86 | QThread * tmp;
87 | for (unsigned int i = 0; i < size;++i)
88 | {
89 | tmp = new QThread;
90 | #ifndef Q_OS_WIN
91 | tmp->setEventDispatcher(new EventDispatcherLibEv());
92 | #endif
93 | threadSize.insert(tmp,0);
94 | tmp->start();
95 | }
96 | }
97 |
98 | QThread * ThreadHandle::findHandleSize() //查找到线程里的连接数小于最大值就返回查找到的,找不到就新建一个线程
99 | {
100 | for (auto it = threadSize.begin();it != threadSize.end() ;++it)
101 | {
102 | if (it.value() < size)
103 | {
104 | it.value() ++;
105 | return it.key();
106 | }
107 | }
108 | QThread * tmp = new QThread;
109 | #ifndef Q_OS_WIN
110 | tmp->setEventDispatcher(new EventDispatcherLibEv());
111 | #endif
112 | threadSize.insert(tmp,1);
113 | tmp->start();
114 | return tmp;
115 | }
116 |
117 | QThread *ThreadHandle::findThreadSize() //遍历查找所有线程中连接数最小的那个,返回
118 | {
119 | auto it = threadSize.begin();
120 | auto ite = threadSize.begin();
121 | for (++it ; it != threadSize.end(); ++it)
122 | {
123 | if (it.value() < ite.value())
124 | {
125 | ite = it;
126 | }
127 | }
128 | ite.value() ++;
129 | return ite.key();
130 | }
131 |
132 | void ThreadHandle::clear()//仅仅清空计数,线程不释放
133 | {
134 | for (auto it = threadSize.begin();it != threadSize.end() ;++it)
135 | {
136 | it.value() = 0;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Server/threadhandle.h:
--------------------------------------------------------------------------------
1 | #ifndef THREADHANDLE_H
2 | #define THREADHANDLE_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | //线程管理类,类似于一个线程池,单例类
9 | //两种初始化方式,一种是每个线程处理的连接数,一个是一共多少个线程
10 | class ThreadHandle
11 | {
12 | public:
13 | ~ThreadHandle();
14 |
15 |
16 | enum ThreadType
17 | {
18 | THREADSIZE, //固定线程数
19 | HANDLESIZE //固定每个线程处理多少连接
20 | };
21 |
22 | static ThreadHandle & getClass(); //返回对象引用,是单例类
23 |
24 | QThread * getThread(); //取出应该移入的线程
25 | void initThreadType(ThreadType type = HANDLESIZE,unsigned int max = 1000);//初始化线程管理的方式
26 | void removeThread(QThread *);//连接断开,线程计数减一
27 | void clear();//清空计数
28 |
29 | protected:
30 | void initThreadSize();//新建固定线程和启动
31 | QThread * findThreadSize();//固定线程数的查找
32 | QThread *findHandleSize();//固定连接数查找
33 | private:
34 | ThreadHandle();
35 | ThreadType type;//线程类型
36 | unsigned int size;//最大值
37 | QHash threadSize;//保存每个线程的数目
38 | bool initfist;//是否是第一次初始化,只允许初始化一次。
39 |
40 | };
41 |
42 | #endif // THREADHANDLE_H
43 |
--------------------------------------------------------------------------------
/test-client/TestClient/TestClient.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2013-09-18T08:44:16
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui network
8 |
9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 |
11 | TARGET = TestClient
12 | TEMPLATE = app
13 |
14 | CONFIG += C++11
15 |
16 | SOURCES += main.cpp\
17 | mainwindow.cpp \
18 | testsockets.cpp \
19 | tcpsocket.cpp
20 |
21 | HEADERS += mainwindow.h \
22 | testsockets.h \
23 | tcpsocket.h
24 |
25 | FORMS += mainwindow.ui
26 |
--------------------------------------------------------------------------------
/test-client/TestClient/main.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication a(argc, argv);
7 | MainWindow w;
8 | w.show();
9 |
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/test-client/TestClient/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include "ui_mainwindow.h"
3 |
4 | MainWindow::MainWindow(QWidget *parent) :
5 | QMainWindow(parent),
6 | ui(new Ui::MainWindow)
7 | {
8 | ui->setupUi(this);
9 | this->ui->timeBut->setEnabled(false);
10 | this->ui->txtIp->setText("127.0.0.1");
11 | this->ui->txtPort->setText("6666");
12 | }
13 |
14 | MainWindow::~MainWindow()
15 | {
16 | delete ui;
17 | }
18 |
19 | void MainWindow::on_pushConnect_clicked()
20 | {
21 | qDebug() << "点击连接:" ;
22 | if ("连接" == this->ui->pushConnect->text())
23 | {
24 | QString ipAdd(this->ui->txtIp->text()), portd(this->ui->txtPort->text());
25 | if (ipAdd.isEmpty() || portd.isEmpty())
26 | {
27 | this->ui->textEdit->append("请输入IP和端口!");
28 | return;
29 | }
30 | if(tcps == nullptr)
31 | {
32 | tcps = new TestSockets;
33 | connect(this,&MainWindow::con,tcps,&TestSockets::connectsocket);
34 | connect(this,&MainWindow::discon,tcps,&TestSockets::disconnectsoc);
35 | connect(tcps,&TestSockets::sentstring,[&](const QString & str){this->ui->textEdit->append(str);});
36 | connect(&tm,&QTimer::timeout,tcps,&TestSockets::sent);
37 | }
38 | emit con(this->ui->txtIp->text(),this->ui->txtPort->text().toInt());
39 | ui->pushConnect->setText("断开");
40 | ui->textEdit->append("连接服务器成功");
41 | this->ui->txtIp->setEnabled(false);
42 | this->ui->txtPort->setEnabled(false);
43 | this->ui->timeBut->setEnabled(true);
44 |
45 | }
46 | else
47 | {
48 | ui->pushConnect->setText("连接");
49 | ui->textEdit->append("断开服务器");
50 | this->ui->txtIp->setEnabled(true);
51 | this->ui->txtPort->setEnabled(true);
52 | emit this->discon();
53 | tm.stop();
54 | this->ui->timeBut->setEnabled(false);
55 | this->ui->lineEdit->setEnabled(true);
56 | this->ui->timeBut->setText("启动定时");
57 |
58 | }
59 | }
60 |
61 | void MainWindow::on_timeBut_clicked()
62 | {
63 | if (this->ui->lineEdit->text().isEmpty())
64 | {
65 | this->ui->textEdit->append("请输入时间:");
66 | return;
67 | }
68 | if ("启动定时" == this->ui->timeBut->text())
69 | {
70 | int h = this->ui->lineEdit->text().toInt();
71 | h = h*1000;
72 | tm.start(h);
73 | this->ui->lineEdit->setEnabled(false);
74 | this->ui->timeBut->setText("停止定时");
75 | }
76 | else
77 | {
78 | tm.stop();
79 | this->ui->timeBut->setText("启动定时");
80 | this->ui->lineEdit->setEnabled(true);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/test-client/TestClient/mainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINWINDOW_H
2 | #define MAINWINDOW_H
3 |
4 | #include
5 | #include
6 | #include "testsockets.h"
7 |
8 | namespace Ui {
9 | class MainWindow;
10 | }
11 |
12 | class MainWindow : public QMainWindow
13 | {
14 | Q_OBJECT
15 |
16 | public:
17 | explicit MainWindow(QWidget *parent = 0);
18 | ~MainWindow();
19 |
20 | signals:
21 | void con(const QString & str, int port);
22 | void discon();
23 |
24 | public slots:
25 | void on_pushConnect_clicked();
26 | void on_timeBut_clicked();
27 |
28 | // void setdata(const QString & str);
29 | private:
30 | Ui::MainWindow * ui;
31 | TestSockets * tcps = nullptr;
32 | QTimer tm;
33 | };
34 |
35 | #endif // MAINWINDOW_H
36 |
--------------------------------------------------------------------------------
/test-client/TestClient/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 431
10 | 466
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 | -
19 |
20 |
21 | -
22 |
23 |
-
24 |
25 |
26 | IP地址:
27 |
28 |
29 |
30 | -
31 |
32 |
33 |
34 | 0
35 | 0
36 |
37 |
38 |
39 | QLineEdit::Normal
40 |
41 |
42 |
43 | -
44 |
45 |
46 | 端口:
47 |
48 |
49 |
50 | -
51 |
52 |
53 |
54 | 0
55 | 0
56 |
57 |
58 |
59 |
60 | 60
61 | 0
62 |
63 |
64 |
65 |
66 | 60
67 | 16777215
68 |
69 |
70 |
71 |
72 | -
73 |
74 |
75 | 连接
76 |
77 |
78 |
79 |
80 |
81 | -
82 |
83 |
-
84 |
85 |
86 | Qt::Horizontal
87 |
88 |
89 |
90 | 188
91 | 18
92 |
93 |
94 |
95 |
96 | -
97 |
98 |
99 | 间隔时间(s):
100 |
101 |
102 |
103 | -
104 |
105 |
106 |
107 | 50
108 | 20
109 |
110 |
111 |
112 |
113 | 50
114 | 0
115 |
116 |
117 |
118 |
119 | 50
120 | 16777215
121 |
122 |
123 |
124 |
125 | -
126 |
127 |
128 | 启动定时
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/test-client/TestClient/tcpsocket.cpp:
--------------------------------------------------------------------------------
1 | #include "tcpsocket.h"
2 | #include
3 | #include
4 |
5 | TcpSocket::TcpSocket(QObject *parent) :
6 | QTcpSocket(parent)
7 | {
8 | connect(this,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(ReadError(QAbstractSocket::SocketError)));
9 | connect(this,&TcpSocket::readyRead,[&](){QString str(QString::number(this->peerPort())); str += " : ";
10 | str += this->readAll(); emit this->sentdata(str);});
11 | }
12 |
13 | void TcpSocket::cth(const QString &host, int port)
14 | {
15 | this->connectToHost(host,port);
16 | this->waitForConnected(5000);
17 | }
18 |
19 | void TcpSocket::sent()
20 | {
21 | if (this->state() == QAbstractSocket::ConnectedState)
22 | {
23 | this->write(QUuid::createUuid().toByteArray());
24 | tm.start();
25 | }
26 | }
27 |
28 | void TcpSocket::ReadError(QAbstractSocket::SocketError)
29 | {
30 | QString str(QString::number(this->peerPort()));
31 | str += " : erro : ";
32 | str += this->errorString();
33 | emit senterro(str);
34 | }
35 |
--------------------------------------------------------------------------------
/test-client/TestClient/tcpsocket.h:
--------------------------------------------------------------------------------
1 | #ifndef TCPSOCKET_H
2 | #define TCPSOCKET_H
3 |
4 | #include
5 | #include
6 |
7 |
8 | class TcpSocket : public QTcpSocket
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit TcpSocket(QObject *parent = 0);
13 |
14 | signals:
15 | void sentdata(const QString & str);
16 | void senterro(const QString & erro);
17 | public slots:
18 | void cth(const QString &host, int port);
19 | void sent();
20 |
21 | void ReadError(QAbstractSocket::SocketError);
22 |
23 | protected:
24 | QTime tm;
25 | };
26 |
27 | #endif // TCPSOCKET_H
28 |
--------------------------------------------------------------------------------
/test-client/TestClient/testsockets.cpp:
--------------------------------------------------------------------------------
1 | #include "testsockets.h"
2 |
3 | TestSockets::TestSockets(QObject *parent) :
4 | QObject(parent)
5 | {
6 | QThread * th;
7 | th = new QThread(this);
8 | th->start();
9 | for (int i = 1; i <= 500 ; ++i)
10 | {
11 | TcpSocket * tmp = new TcpSocket;
12 | connect(this,&TestSockets::connectsocket,tmp,&TcpSocket::cth);
13 | connect(this,&TestSockets::sent,tmp,&TcpSocket::sent);
14 | connect(tmp,&TcpSocket::sentdata,this,&TestSockets::sentstring);
15 | connect(tmp,&TcpSocket::senterro,this,&TestSockets::sentstring);
16 | connect(this,&TestSockets::disconnectsoc,tmp,&TcpSocket::disconnectFromHost);
17 | if (i %20 == 0)
18 | {
19 | th = new QThread(this);
20 | th->start();
21 | }
22 | tmp->moveToThread(th);
23 | }
24 | }
25 |
26 | TestSockets::~TestSockets()
27 | {
28 | qDeleteAll(tcps);
29 | }
30 |
--------------------------------------------------------------------------------
/test-client/TestClient/testsockets.h:
--------------------------------------------------------------------------------
1 | #ifndef TESTSOCKETS_H
2 | #define TESTSOCKETS_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include "tcpsocket.h"
8 |
9 | class TestSockets : public QObject
10 | {
11 | Q_OBJECT
12 | public:
13 | explicit TestSockets(QObject *parent = 0);
14 | ~TestSockets();
15 |
16 | signals:
17 | void sent();
18 | void connectsocket(const QString & ip, int port);
19 | void sentstring(const QString & str);
20 | void disconnectsoc();
21 | public slots:
22 |
23 | private:
24 | QList tcps;
25 | };
26 |
27 | #endif // TESTSOCKETS_H
28 |
--------------------------------------------------------------------------------
/test-client/myTcpClient/main.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication a(argc, argv);
7 | MainWindow w;
8 | w.show();
9 |
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/test-client/myTcpClient/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include "ui_mainwindow.h"
3 |
4 | MainWindow::MainWindow(QWidget *parent) :
5 | QMainWindow(parent),
6 | ui(new Ui::MainWindow)
7 | {
8 | ui->setupUi(this);
9 | tcpClient = new QTcpSocket(this);
10 | ui->pushSent->setEnabled(false);
11 | this->ui->timeBut->setEnabled(false);
12 | tcpClient->abort();
13 | connect(tcpClient,&QTcpSocket::readyRead,
14 | [&](){this->ui->textEdit->append(tr("%1 Server Say:%2").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(QString(this->tcpClient->readAll())));});
15 | connect(tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(ReadError(QAbstractSocket::SocketError)));
16 | connect(&tm,&QTimer::timeout,[&](){
17 | int i = qrand() % 6;
18 | this->ui->textEdit->append(tr("%1 Timer Sent: %2").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(list.at(i)));
19 | tcpClient->write(list.at(i).toUtf8());
20 | });
21 | connect(tcpClient,&QTcpSocket::disconnected,[](){qDebug()<< "123333" ;});
22 | list << "我是谁?" << "渡世白玉" << "hello" << "哈哈哈哈哈" << "你是坏蛋!" << "测试一下下了" << "不知道写什么" ;
23 | QTime time;
24 | time= QTime::currentTime();
25 | qsrand(time.msec()+time.second()*1000);
26 | this->ui->txtIp->setText("127.0.0.1");
27 | this->ui->txtPort->setText("6666");
28 | }
29 |
30 | MainWindow::~MainWindow()
31 | {
32 | delete ui;
33 | delete tcpClient;
34 | }
35 |
36 | void MainWindow::on_pushConnect_clicked()
37 | {
38 | qDebug() << "点击连接:" ;
39 | if ("连接" == this->ui->pushConnect->text())
40 | {
41 | QString ipAdd(this->ui->txtIp->text()), portd(this->ui->txtPort->text());
42 | if (ipAdd.isEmpty() || portd.isEmpty())
43 | {
44 | this->ui->textEdit->append("请输入IP和端口!");
45 | return;
46 | }
47 | tcpClient->connectToHost(ipAdd,portd.toInt());
48 | if (tcpClient->waitForConnected(1000))
49 | {
50 | ui->pushConnect->setText("断开");
51 | ui->textEdit->append("连接服务器成功");
52 | ui->pushSent->setEnabled(true);
53 | this->ui->txtIp->setEnabled(false);
54 | this->ui->txtPort->setEnabled(false);
55 | this->ui->timeBut->setEnabled(true);
56 | }
57 | }
58 | else
59 | {
60 | tcpClient->disconnectFromHost();
61 | if (tcpClient->state() == QAbstractSocket::UnconnectedState || tcpClient->waitForDisconnected(1000) )
62 | {
63 | ui->pushConnect->setText("连接");
64 | ui->textEdit->append("断开服务器");
65 | ui->pushSent->setEnabled(false);
66 | this->ui->txtIp->setEnabled(true);
67 | this->ui->txtPort->setEnabled(true);
68 | tm.stop();
69 | this->ui->timeBut->setEnabled(false);
70 | this->ui->lineEdit->setEnabled(true);
71 | this->ui->timeBut->setText("启动定时");
72 | }
73 | }
74 | }
75 |
76 | void MainWindow::on_pushSent_clicked()
77 | {
78 | qDebug() << "点击发送:" ;
79 | QString data = this->ui->txtData->toPlainText();//->text();
80 | if (data.isEmpty())
81 | {
82 | return ;
83 | }
84 | tcpClient->write(data.toUtf8());
85 | ui->textEdit->append(tr("Say:%1").arg(data));
86 | }
87 |
88 | void MainWindow::ReadError(QAbstractSocket::SocketError)
89 | {
90 | tcpClient->disconnectFromHost();
91 | ui->pushConnect->setText("连接");
92 | ui->textEdit->append(tr("连接出错:%1").arg(tcpClient->errorString()));
93 | ui->pushSent->setEnabled(false);
94 | this->ui->txtIp->setEnabled(true);
95 | this->ui->txtPort->setEnabled(true);
96 | tm.stop();
97 | this->ui->timeBut->setEnabled(false);
98 | this->ui->lineEdit->setEnabled(true);
99 | this->ui->timeBut->setText("启动定时");
100 | }
101 |
102 | void MainWindow::on_timeBut_clicked()
103 | {
104 | if (this->ui->lineEdit->text().isEmpty())
105 | {
106 | this->ui->textEdit->append("请输入时间:");
107 | return;
108 | }
109 | if ("启动定时" == this->ui->timeBut->text())
110 | {
111 | int h = this->ui->lineEdit->text().toInt();
112 | h = h*1000;
113 | tm.start(h);
114 | this->ui->lineEdit->setEnabled(false);
115 | this->ui->timeBut->setText("停止定时");
116 | }
117 | else
118 | {
119 | tm.stop();
120 | this->ui->timeBut->setText("启动定时");
121 | this->ui->lineEdit->setEnabled(true);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/test-client/myTcpClient/mainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINWINDOW_H
2 | #define MAINWINDOW_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | namespace Ui {
9 | class MainWindow;
10 | }
11 |
12 | class MainWindow : public QMainWindow
13 | {
14 | Q_OBJECT
15 |
16 | public:
17 | explicit MainWindow(QWidget *parent = 0);
18 | ~MainWindow();
19 |
20 | public slots:
21 | void ReadError(QAbstractSocket::SocketError);
22 |
23 | void on_pushSent_clicked();
24 | void on_pushConnect_clicked();
25 | void on_timeBut_clicked();
26 |
27 | private:
28 | Ui::MainWindow * ui;
29 | QTcpSocket * tcpClient;
30 | QTimer tm;
31 | QStringList list;
32 | };
33 |
34 | #endif // MAINWINDOW_H
35 |
--------------------------------------------------------------------------------
/test-client/myTcpClient/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 504
10 | 505
11 |
12 |
13 |
14 | MainWindow
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 | IP地址:
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 | 0
56 | 0
57 |
58 |
59 |
60 | QLineEdit::Normal
61 |
62 |
63 |
64 | -
65 |
66 |
67 | 端口:
68 |
69 |
70 |
71 | -
72 |
73 |
74 |
75 | 0
76 | 0
77 |
78 |
79 |
80 |
81 | 60
82 | 0
83 |
84 |
85 |
86 |
87 | 60
88 | 16777215
89 |
90 |
91 |
92 |
93 | -
94 |
95 |
96 | 连接
97 |
98 |
99 |
100 |
101 |
102 | -
103 |
104 |
-
105 |
106 |
107 | Qt::Horizontal
108 |
109 |
110 |
111 | 188
112 | 18
113 |
114 |
115 |
116 |
117 | -
118 |
119 |
120 | 间隔时间(s):
121 |
122 |
123 |
124 | -
125 |
126 |
127 |
128 | 50
129 | 20
130 |
131 |
132 |
133 |
134 | 50
135 | 0
136 |
137 |
138 |
139 |
140 | 50
141 | 16777215
142 |
143 |
144 |
145 |
146 | -
147 |
148 |
149 | 启动定时
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/test-client/myTcpClient/myTcpClient.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2013-09-18T08:44:16
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui network
8 |
9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 |
11 | TARGET = myTcpClient
12 | TEMPLATE = app
13 |
14 | CONFIG += C++11
15 |
16 | SOURCES += main.cpp\
17 | mainwindow.cpp
18 |
19 | HEADERS += mainwindow.h
20 |
21 | FORMS += mainwindow.ui
22 |
--------------------------------------------------------------------------------