├── README.md ├── dayFive ├── Makefile ├── MyReactor.cpp ├── MyReactor.h ├── README.md └── main.cpp ├── dayFour ├── Makefile ├── MyReactor.cpp ├── MyReactor.h ├── README.md └── main.cpp ├── dayOne ├── Makefile ├── README.md ├── client.c └── server.c ├── daySix ├── Chat+mysql │ ├── Makefile │ ├── MyReactor.cpp │ ├── MyReactor.h │ ├── command.h │ ├── main │ └── main.cpp ├── ChatRoom │ ├── ChatRoom.pro │ ├── ChatRoom.pro.user │ ├── ChatRoom.pro.user.0360db3 │ ├── ChatRoom.pro.user.b25dcfa │ ├── addfriends.cpp │ ├── addfriends.h │ ├── chatroom.cpp │ ├── chatroom.h │ ├── command.h │ ├── drawer.cpp │ ├── drawer.h │ ├── images.qrc │ ├── images │ │ ├── ChatRoom.jpg │ │ ├── Linux.jpg │ │ ├── liu.png │ │ └── qq.png │ ├── information.h │ ├── main.cpp │ ├── sign.cpp │ ├── sign.h │ ├── tcpclient.cpp │ ├── tcpclient.h │ ├── widget.cpp │ ├── widget.h │ └── widget.ui ├── ChatRoomV0.1.PNG └── README.md ├── dayThree ├── README.md ├── TcpClient.png ├── TcpClient │ ├── TcpClient.pro │ ├── TcpClient.pro.user │ ├── TcpClient.pro.user.49007d5 │ ├── main.cpp │ ├── tcpclient.cpp │ └── tcpclient.h ├── TcpClient2.png ├── bin │ └── TcpClient └── chatRoomV0.1.png └── dayTwo ├── README.md ├── TcpClientV0.01.png ├── communication.png ├── communication ├── communication.pro ├── communication.pro.user ├── communication.pro.user.0360db3 ├── dialog.cpp ├── dialog.h └── main.cpp └── communication2.png /README.md: -------------------------------------------------------------------------------- 1 | # chatRoom 2 | 3 | ## dayOne 4 | 1. 首先实现一个简单的聊天室服务器,基于之前所学的Linux网络编程的知识 5 | 2. 客户端可以自己实现,也可以直接使用nc命令或telnet命令来充当客户端 6 | 7 | ## dayTwo 8 | 学习qt,并实现一个能和服务端连接上并且能交流的一个TCP客户端demo 9 | 10 | ### Linux环境下运行的TCP客户端: 11 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayTwo/communication.png) 12 | 13 | ### Windows7环境下运行的TCP客户端: 14 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayTwo/communication2.png) 15 | 16 | ### 与dayOne实现的服务器一起运行: 17 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayTwo/TcpClientV0.01.png) 18 | 19 | 20 | ## dayThree 21 | 学习qt,然后写出一个图形界面的客户端,暂时先不考虑没不美观、只考虑功能实现 22 | 23 | ### Linux环境下运行的客户端: 24 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayThree/TcpClient.png) 25 | 26 | ### Windows7环境下运行的客户端: 27 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayThree/TcpClient2.png) 28 | 29 | ### 与dayOne实现的服务器一起运行: 30 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayThree/chatRoomV0.1.png) 31 | 32 | ## dayFour 33 | 今天把注意力放在服务器,之前写的服务器有点看不过去,现在写一个reactor模式的聊天服务器,这样服务器的并发性能更好 34 | 35 | 36 | ## dayFive 37 | 今天继续修改dayFour写的服务器,加上日志的功能 38 | 为了方便(偷懒),日志采用开源库[spdlog](https://github.com/gabime/spdlog/) 39 | 40 | 41 | ## daySix 42 | 今天再把重心转向客户端,我们都知道一般的聊天软件肯定都要账号和密码,我们今天就实现它 43 | 44 | ### ChatRoom与Chat+mysql中的服务器一起运行: 45 | #### (Chat+MySQL是由之前的服务器加上了MySQL数据库的操作,还不完善) 46 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/daySix/ChatRoomV0.1.PNG) 47 | 48 | 49 | ## 注意! 50 | 1. 在dayFive时添加的依赖库要自行添加,不然直接make会报错 51 | 2. 在客户端中要注意可能要修改IP地址,这取决于你怎么实验,我的服务器端已经部署到阿里云服务器上了,IP地址为120.79.214.120 52 | 3. 由于我还在学习当中,代码可能不怎么好看,而且客户端实在有些难看。不过如果你喜欢的话,可以顺手点一下star。 53 | 54 | 感谢赞助!如果此项目对您有帮助,请作者喝一杯奶茶~~ (开心一整天😊😊) 55 | ![image](https://github.com/user-attachments/assets/00b1ffbd-b63a-40f5-8f68-a870d3a9aeeb) 56 | ![image](https://github.com/user-attachments/assets/6f8c0492-ace7-4679-b5ea-ed9029efb192) 57 | -------------------------------------------------------------------------------- /dayFive/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ -g -Wall -o main main.cpp MyReactor.cpp -I ../dep/spdlog/include/ -pthread 3 | 4 | clean: 5 | rm -rf main 6 | -------------------------------------------------------------------------------- /dayFive/MyReactor.cpp: -------------------------------------------------------------------------------- 1 | #include "MyReactor.h" 2 | 3 | #include "spdlog/sinks/daily_file_sink.h" 4 | #include "spdlog/sinks/basic_file_sink.h" 5 | /* static auto my_logger = spdlog::my_logger_mt("my_logger", "logs/daily.txt", 18, 53); */ 6 | /* auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt"); */ 7 | auto my_logger = spdlog::stdout_color_mt("my_logger"); 8 | 9 | MyReactor::MyReactor() 10 | { 11 | } 12 | 13 | MyReactor::~MyReactor() 14 | { 15 | } 16 | 17 | struct ARG 18 | { 19 | MyReactor* pThis; 20 | }; 21 | 22 | bool MyReactor::init(const char* ip, short nport) 23 | { 24 | if(!create_server_listener(ip, nport)) 25 | { 26 | my_logger->error("Unable to bind: {0} : {1}.", ip, nport); 27 | return false; 28 | } 29 | 30 | ARG *arg = new ARG(); 31 | arg->pThis = this; 32 | 33 | pthread_create(&m_accept_threadid, NULL, accept_thread_proc, (void*)arg); 34 | 35 | pthread_create(&m_send_threadid, NULL, send_thread_proc, (void*)arg); 36 | 37 | for(int i = 0; i < WORKER_THREAD_NUM; i++) 38 | { 39 | pthread_create(&m_threadid[i], NULL, worker_thread_proc, (void*)arg); 40 | } 41 | 42 | return true; 43 | } 44 | 45 | 46 | bool MyReactor::uninit() 47 | { 48 | m_bStop = true; 49 | 50 | /* 将读端和写端都关闭 */ 51 | shutdown(m_listenfd, SHUT_RDWR); 52 | close(m_listenfd); 53 | close(m_epollfd); 54 | 55 | return true; 56 | } 57 | 58 | 59 | void* MyReactor::main_loop(void *p) 60 | { 61 | my_logger->info("main thread id = {}", pthread_self()); 62 | 63 | MyReactor* pReactor = static_cast(p); 64 | 65 | while(!pReactor->m_bStop) 66 | { 67 | /* std::cout << "main loop" << std::endl; */ 68 | struct epoll_event ev[1024]; 69 | int n = epoll_wait(pReactor->m_epollfd, ev, 1024, 10); 70 | if(n == 0) 71 | continue; 72 | else if(n < 0) 73 | { 74 | my_logger->error("epoll_wait error"); 75 | continue; 76 | } 77 | 78 | int m = std::min(n, 1024); 79 | for(int i = 0; i < m; i++) 80 | { 81 | /* 有新连接 */ 82 | if(ev[i].data.fd == pReactor->m_listenfd) 83 | pthread_cond_signal(&pReactor->m_accept_cond); 84 | /* 有数据 */ 85 | else 86 | { 87 | pthread_mutex_lock(&pReactor->m_client_mutex); 88 | pReactor->m_clientlist.push_back(ev[i].data.fd); 89 | pthread_mutex_unlock(&pReactor->m_client_mutex); 90 | pthread_cond_signal(&pReactor->m_client_cond); 91 | } 92 | } 93 | } 94 | 95 | my_logger->info("main loop exit ..."); 96 | return NULL; 97 | } 98 | 99 | 100 | bool MyReactor::close_client(int clientfd) 101 | { 102 | if(epoll_ctl(m_epollfd, EPOLL_CTL_DEL, clientfd, NULL) == -1) 103 | { 104 | my_logger->warn("release client socket failed as call epoll_ctl fail"); 105 | } 106 | 107 | close(clientfd); 108 | return true; 109 | } 110 | 111 | 112 | bool MyReactor::create_server_listener(const char* ip, short port) 113 | { 114 | m_listenfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); 115 | if(m_listenfd == -1) 116 | { 117 | my_logger->error("fail to create a socket"); 118 | return false; 119 | } 120 | 121 | int on = 1; 122 | setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); 123 | setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)); 124 | 125 | struct sockaddr_in servaddr; 126 | memset(&servaddr, 0, sizeof(servaddr)); 127 | servaddr.sin_family = AF_INET; 128 | servaddr.sin_addr.s_addr = inet_addr(ip); 129 | servaddr.sin_port = htons(port); 130 | 131 | if(bind(m_listenfd, (sockaddr *)&servaddr, sizeof(servaddr)) == -1) 132 | return false; 133 | 134 | if(listen(m_listenfd, 50) == -1) 135 | return false; 136 | 137 | m_epollfd = epoll_create(1); 138 | if(m_epollfd == -1) 139 | return false; 140 | 141 | struct epoll_event e; 142 | memset(&e, 0, sizeof(e)); 143 | e.events = EPOLLIN | EPOLLRDHUP; 144 | e.data.fd = m_listenfd; 145 | if(epoll_ctl(m_epollfd, EPOLL_CTL_ADD, m_listenfd, &e) == -1) 146 | return false; 147 | 148 | return true; 149 | } 150 | 151 | 152 | void* MyReactor::accept_thread_proc(void* args) 153 | { 154 | ARG *arg = (ARG*)args; 155 | MyReactor* pReactor = arg->pThis; 156 | 157 | while(!pReactor->m_bStop) 158 | { 159 | pthread_mutex_lock(&pReactor->m_accept_mutex); 160 | pthread_cond_wait(&pReactor->m_accept_cond, &pReactor->m_accept_mutex); 161 | 162 | struct sockaddr_in clientaddr; 163 | socklen_t addrlen; 164 | int newfd = accept(pReactor->m_listenfd, (struct sockaddr *)&clientaddr, &addrlen); 165 | pthread_mutex_unlock(&pReactor->m_accept_mutex); 166 | if(newfd == -1) 167 | continue; 168 | 169 | 170 | pthread_mutex_lock(&pReactor->m_cli_mutex); 171 | pReactor->m_fds.insert(newfd); 172 | pthread_mutex_unlock(&pReactor->m_cli_mutex); 173 | 174 | my_logger->info("new client connected: "); 175 | 176 | /* 将新socket设置为non-blocking */ 177 | int oldflag = fcntl(newfd, F_GETFL, 0); 178 | int newflag = oldflag | O_NONBLOCK; 179 | if(fcntl(newfd, F_SETFL, newflag) == -1) 180 | { 181 | my_logger->error("fcntl error, oldflag = {0}, newflag = {1}", oldflag, newflag); 182 | continue; 183 | } 184 | 185 | struct epoll_event e; 186 | memset(&e, 0, sizeof(e)); 187 | e.events = EPOLLIN | EPOLLRDHUP | EPOLLET; 188 | e.data.fd = newfd; 189 | /* 添加进epoll的兴趣列表 */ 190 | if(epoll_ctl(pReactor->m_epollfd, EPOLL_CTL_ADD, newfd, &e) == -1) 191 | { 192 | my_logger->error("epoll_ctl error, fd = {}", newfd); 193 | } 194 | } 195 | 196 | return NULL; 197 | } 198 | 199 | void* MyReactor::worker_thread_proc(void* args) 200 | { 201 | ARG *arg = (ARG*)args; 202 | MyReactor* pReactor = arg->pThis; 203 | 204 | while(!pReactor->m_bStop) 205 | { 206 | int clientfd; 207 | pthread_mutex_lock(&pReactor->m_client_mutex); 208 | /* 注意!要用while循环等待 */ 209 | while(pReactor->m_clientlist.empty()) 210 | pthread_cond_wait(&pReactor->m_client_cond, &pReactor->m_client_mutex); 211 | 212 | /* 取出客户套接字 */ 213 | clientfd = pReactor->m_clientlist.front(); 214 | pReactor->m_clientlist.pop_front(); 215 | pthread_mutex_unlock(&pReactor->m_client_mutex); 216 | 217 | std::cout << std::endl; 218 | 219 | 220 | std::string strclientmsg; 221 | char buff[256]; 222 | bool bError = false; 223 | while(1) 224 | { 225 | memset(buff, 0, sizeof(buff)); 226 | int nRecv = recv(clientfd, buff, 256, 0); 227 | if(nRecv == -1) 228 | { 229 | if(errno == EWOULDBLOCK) 230 | break; 231 | else 232 | { 233 | my_logger->error("recv error, client disconnected, fd = {}", clientfd); 234 | pReactor->close_client(clientfd); 235 | bError = true; 236 | break; 237 | } 238 | } 239 | /* 对端关闭了socket,这端也关闭 */ 240 | else if(nRecv == 0) 241 | { 242 | /* 将该客户从客户列表中删除 */ 243 | pthread_mutex_lock(&pReactor->m_cli_mutex); 244 | pReactor->m_fds.erase(clientfd); 245 | pthread_mutex_unlock(&pReactor->m_cli_mutex); 246 | 247 | my_logger->info("peer closed, client disconnected, fd = {}", clientfd); 248 | pReactor->close_client(clientfd); 249 | bError = true; 250 | break; 251 | } 252 | 253 | strclientmsg += buff; 254 | } 255 | 256 | /* 如果出错了就不必往下执行了 */ 257 | if(bError) 258 | { 259 | continue; 260 | } 261 | 262 | my_logger->info("client msg: {}", strclientmsg); 263 | 264 | /* 将消息加上时间戳 */ 265 | time_t now = time(NULL); 266 | struct tm* nowstr = localtime(&now); 267 | std::ostringstream ostimestr; 268 | ostimestr << "[" << nowstr->tm_year + 1900 << "-" 269 | << std::setw(2) << std::setfill('0') << nowstr->tm_mon + 1 << "-" 270 | << std::setw(2) << std::setfill('0') << nowstr->tm_mday << " " 271 | << std::setw(2) << std::setfill('0') << nowstr->tm_hour << ":" 272 | << std::setw(2) << std::setfill('0') << nowstr->tm_min << ":" 273 | << std::setw(2) << std::setfill('0') << nowstr->tm_sec << " :"; 274 | 275 | strclientmsg.insert(0, ostimestr.str()); 276 | 277 | /* 将消息交给发送消息的线程 */ 278 | pReactor->m_msgs.push_back(strclientmsg); 279 | pthread_cond_signal(&pReactor->m_send_cond); 280 | } 281 | return NULL; 282 | } 283 | 284 | 285 | void* MyReactor::send_thread_proc(void *args) 286 | { 287 | ARG *arg = (ARG*)args; 288 | MyReactor* pReactor = arg->pThis; 289 | 290 | while(!pReactor->m_bStop) 291 | { 292 | std::string strclientmsg; 293 | 294 | pthread_mutex_lock(&pReactor->m_send_mutex); 295 | /* 注意!要用while循环等待 */ 296 | while(pReactor->m_msgs.empty()) 297 | pthread_cond_wait(&pReactor->m_send_cond, &pReactor->m_send_mutex); 298 | 299 | strclientmsg = pReactor->m_msgs.front(); 300 | pReactor->m_msgs.pop_front(); 301 | pthread_mutex_unlock(&pReactor->m_send_mutex); 302 | 303 | std::cout << std::endl; 304 | 305 | 306 | while(1) 307 | { 308 | int nSend; 309 | int clientfd; 310 | for(auto it = pReactor->m_fds.begin(); it != pReactor->m_fds.end(); it++) 311 | { 312 | clientfd = *it; 313 | nSend = send(clientfd, strclientmsg.c_str(), strclientmsg.length(), 0); 314 | if(nSend == -1) 315 | { 316 | if(errno == EWOULDBLOCK) 317 | { 318 | sleep(10); 319 | continue; 320 | } 321 | else 322 | { 323 | my_logger->error("send error, fd = {}", clientfd); 324 | pReactor->close_client(clientfd); 325 | break; 326 | } 327 | } 328 | } 329 | 330 | my_logger->info("send: {}", strclientmsg); 331 | /* 发送完把缓冲区清干净 */ 332 | strclientmsg.clear(); 333 | 334 | if(strclientmsg.empty()) 335 | break; 336 | } 337 | } 338 | 339 | return NULL; 340 | } 341 | -------------------------------------------------------------------------------- /dayFive/MyReactor.h: -------------------------------------------------------------------------------- 1 | #ifndef __MYREACTOR_H 2 | #define __MYREACTOR_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include //for htonl() and htons() 11 | #include 12 | #include 13 | #include 14 | #include //for signal() 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include //for std::setw()/setfill() 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include "spdlog/spdlog.h" 31 | #include "spdlog/sinks/stdout_color_sinks.h" 32 | 33 | 34 | #define WORKER_THREAD_NUM 5 35 | 36 | 37 | class MyReactor{ 38 | public: 39 | MyReactor(); 40 | ~MyReactor(); 41 | 42 | /* 初始化socket和线程,供应用程序调用 */ 43 | bool init(const char *ip, short nport); 44 | 45 | bool uninit(); 46 | 47 | bool close_client(int clientfd); 48 | 49 | static void* main_loop(void* loop); 50 | 51 | private: 52 | /* 见条款6,阻止有人调用复制构造函数和赋值运算符构造函数 */ 53 | MyReactor(const MyReactor& rhs); 54 | MyReactor& operator = (const MyReactor& rhs); 55 | 56 | static void *accept_thread_proc(void* args); 57 | static void *worker_thread_proc(void* args); 58 | 59 | static void *send_thread_proc(void* args); 60 | 61 | bool create_server_listener(const char* ip, short port); 62 | 63 | 64 | private: 65 | /* 服务器端的socket */ 66 | int m_listenfd = 0; 67 | /* 让线程可以修改它 */ 68 | int m_epollfd = 0; 69 | /* 线程ID */ 70 | pthread_t m_accept_threadid; 71 | pthread_t m_threadid[WORKER_THREAD_NUM]; 72 | 73 | pthread_t m_send_threadid; 74 | 75 | /* 接受客户的信号量 */ 76 | pthread_mutex_t m_accept_mutex = PTHREAD_MUTEX_INITIALIZER; 77 | /* 有新连接的条件变量 */ 78 | pthread_cond_t m_accept_cond = PTHREAD_COND_INITIALIZER; 79 | /* 添加、取出客户链表的信号量 */ 80 | pthread_mutex_t m_client_mutex = PTHREAD_MUTEX_INITIALIZER; 81 | /* 通知工作线程有客户消息的条件变量 */ 82 | pthread_cond_t m_client_cond = PTHREAD_COND_INITIALIZER; 83 | 84 | pthread_mutex_t m_send_mutex = PTHREAD_MUTEX_INITIALIZER; 85 | pthread_cond_t m_send_cond = PTHREAD_COND_INITIALIZER; 86 | std::deque m_msgs; 87 | 88 | pthread_mutex_t m_cli_mutex = PTHREAD_MUTEX_INITIALIZER; 89 | pthread_cond_t m_cli_cond = PTHREAD_COND_INITIALIZER; 90 | /* std::vector m_fds; */ 91 | std::set m_fds; 92 | 93 | 94 | /* 存储连接客户的链表 */ 95 | std::list m_clientlist; 96 | 97 | 98 | /* 决定主线程、accept线程、工作线程是否继续迭代 */ 99 | bool m_bStop = false; 100 | }; 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /dayFive/README.md: -------------------------------------------------------------------------------- 1 | ## dayFive 2 | 今天继续修改dayFour写的服务器,加上日志的功能 3 | 为了方便(偷懒),日志采用开源库[spdlog](https://github.com/gabime/spdlog/) 4 | -------------------------------------------------------------------------------- /dayFive/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MyReactor.h" 2 | 3 | 4 | #include "spdlog/sinks/daily_file_sink.h" 5 | #include "spdlog/sinks/basic_file_sink.h" 6 | auto main_logger = spdlog::stdout_color_mt("main_logger"); 7 | 8 | 9 | MyReactor g_reactor; 10 | 11 | 12 | void prog_exit(int signo) 13 | { 14 | main_logger->info("program recv signal {} to exit.", signo); 15 | g_reactor.uninit(); 16 | } 17 | 18 | void daemon_run() 19 | { 20 | int pid; 21 | signal(SIGCHLD, SIG_IGN); 22 | pid = fork(); 23 | if (pid < 0) 24 | { 25 | main_logger->error("fork error"); 26 | exit(-1); 27 | } 28 | else if (pid > 0) { 29 | exit(0); 30 | } 31 | //之前parent和child运行在同一个session里,parent是会话(session)的领头进程, 32 | //parent进程作为会话的领头进程,如果exit结束执行的话,那么子进程会成为孤儿进程,并被init收养。 33 | //执行setsid()之后,child将重新获得一个新的会话(session)id。 34 | //这时parent退出之后,将不会影响到child了。 35 | setsid(); 36 | int fd; 37 | fd = open("/dev/null", O_RDWR, 0); 38 | if (fd != -1) 39 | { 40 | dup2(fd, STDIN_FILENO); 41 | dup2(fd, STDOUT_FILENO); 42 | dup2(fd, STDERR_FILENO); 43 | } 44 | if (fd > 2) 45 | close(fd); 46 | } 47 | 48 | 49 | int main(int argc, char* argv[]) 50 | { 51 | //设置信号处理 52 | signal(SIGCHLD, SIG_DFL); 53 | signal(SIGPIPE, SIG_IGN); 54 | signal(SIGINT, prog_exit); 55 | signal(SIGKILL, prog_exit); 56 | signal(SIGTERM, prog_exit); 57 | 58 | short port = 0; 59 | int ch; 60 | bool bdaemon = false; 61 | while ((ch = getopt(argc, argv, "p:d")) != -1) 62 | { 63 | switch (ch) 64 | { 65 | case 'd': 66 | bdaemon = true; 67 | break; 68 | case 'p': 69 | port = atol(optarg); 70 | break; 71 | } 72 | } 73 | 74 | if (bdaemon) 75 | daemon_run(); 76 | 77 | 78 | if (port == 0) 79 | port = 12345; 80 | 81 | if (!g_reactor.init("0.0.0.0", 12345)) 82 | return -1; 83 | 84 | 85 | g_reactor.main_loop(&g_reactor); 86 | 87 | main_logger->info("main exit"); 88 | 89 | return 0; 90 | } 91 | 92 | 93 | -------------------------------------------------------------------------------- /dayFour/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ -g -Wall main.cpp MyReactor.cpp -o main -lpthread 3 | 4 | 5 | clean: 6 | rm -rf main 7 | -------------------------------------------------------------------------------- /dayFour/MyReactor.cpp: -------------------------------------------------------------------------------- 1 | #include "MyReactor.h" 2 | 3 | MyReactor::MyReactor() 4 | { 5 | } 6 | 7 | MyReactor::~MyReactor() 8 | { 9 | } 10 | 11 | struct ARG 12 | { 13 | MyReactor* pThis; 14 | }; 15 | 16 | bool MyReactor::init(const char* ip, short nport) 17 | { 18 | if(!create_server_listener(ip, nport)) 19 | { 20 | std::cout << "Unable to bind:" << ip << ":" << nport << "." << std::endl; 21 | return false; 22 | } 23 | 24 | std::cout << "main thread id = " << pthread_self() << std::endl; 25 | 26 | ARG *arg = new ARG(); 27 | arg->pThis = this; 28 | 29 | pthread_create(&m_accept_threadid, NULL, accept_thread_proc, (void*)arg); 30 | 31 | pthread_create(&m_send_threadid, NULL, send_thread_proc, (void*)arg); 32 | 33 | std::cout << "accept thread " << std::endl; 34 | 35 | for(int i = 0; i < WORKER_THREAD_NUM; i++) 36 | { 37 | pthread_create(&m_threadid[i], NULL, worker_thread_proc, (void*)arg); 38 | } 39 | 40 | return true; 41 | } 42 | 43 | 44 | bool MyReactor::uninit() 45 | { 46 | m_bStop = true; 47 | 48 | 49 | /* 将读端和写端都关闭 */ 50 | shutdown(m_listenfd, SHUT_RDWR); 51 | close(m_listenfd); 52 | close(m_epollfd); 53 | 54 | return true; 55 | } 56 | 57 | 58 | void* MyReactor::main_loop(void *p) 59 | { 60 | std::cout << "main thread id = " << pthread_self() << std::endl; 61 | 62 | MyReactor* pReactor = static_cast(p); 63 | 64 | 65 | 66 | while(!pReactor->m_bStop) 67 | { 68 | /* std::cout << "main loop" << std::endl; */ 69 | struct epoll_event ev[1024]; 70 | int n = epoll_wait(pReactor->m_epollfd, ev, 1024, 10); 71 | if(n == 0) 72 | continue; 73 | else if(n < 0) 74 | { 75 | std::cout << "epoll_wait error" << std::endl; 76 | continue; 77 | } 78 | 79 | int m = std::min(n, 1024); 80 | for(int i = 0; i < m; i++) 81 | { 82 | /* 有新连接 */ 83 | if(ev[i].data.fd == pReactor->m_listenfd) 84 | pthread_cond_signal(&pReactor->m_accept_cond); 85 | /* 有数据 */ 86 | else 87 | { 88 | pthread_mutex_lock(&pReactor->m_client_mutex); 89 | pReactor->m_clientlist.push_back(ev[i].data.fd); 90 | pthread_mutex_unlock(&pReactor->m_client_mutex); 91 | 92 | 93 | pthread_cond_signal(&pReactor->m_client_cond); 94 | } 95 | } 96 | } 97 | 98 | std::cout << "main loop exit ..." << std::endl; 99 | return NULL; 100 | } 101 | 102 | 103 | bool MyReactor::close_client(int clientfd) 104 | { 105 | if(epoll_ctl(m_epollfd, EPOLL_CTL_DEL, clientfd, NULL) == -1) 106 | { 107 | std::cout << "release client socket failed as call epoll_ctl fail" << std::endl; 108 | } 109 | 110 | close(clientfd); 111 | return true; 112 | } 113 | 114 | 115 | bool MyReactor::create_server_listener(const char* ip, short port) 116 | { 117 | m_listenfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); 118 | if(m_listenfd == -1) 119 | { 120 | return false; 121 | } 122 | 123 | int on = 1; 124 | setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); 125 | setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)); 126 | 127 | struct sockaddr_in servaddr; 128 | memset(&servaddr, 0, sizeof(servaddr)); 129 | servaddr.sin_family = AF_INET; 130 | servaddr.sin_addr.s_addr = inet_addr(ip); 131 | servaddr.sin_port = htons(port); 132 | 133 | if(bind(m_listenfd, (sockaddr *)&servaddr, sizeof(servaddr)) == -1) 134 | return false; 135 | 136 | if(listen(m_listenfd, 50) == -1) 137 | return false; 138 | 139 | m_epollfd = epoll_create(1); 140 | if(m_epollfd == -1) 141 | return false; 142 | 143 | struct epoll_event e; 144 | memset(&e, 0, sizeof(e)); 145 | e.events = EPOLLIN | EPOLLRDHUP; 146 | e.data.fd = m_listenfd; 147 | if(epoll_ctl(m_epollfd, EPOLL_CTL_ADD, m_listenfd, &e) == -1) 148 | return false; 149 | 150 | return true; 151 | } 152 | 153 | 154 | void* MyReactor::accept_thread_proc(void* args) 155 | { 156 | ARG *arg = (ARG*)args; 157 | MyReactor* pReactor = arg->pThis; 158 | 159 | while(!pReactor->m_bStop) 160 | { 161 | pthread_mutex_lock(&pReactor->m_accept_mutex); 162 | pthread_cond_wait(&pReactor->m_accept_cond, &pReactor->m_accept_mutex); 163 | 164 | struct sockaddr_in clientaddr; 165 | socklen_t addrlen; 166 | int newfd = accept(pReactor->m_listenfd, (struct sockaddr *)&clientaddr, &addrlen); 167 | pthread_mutex_unlock(&pReactor->m_accept_mutex); 168 | if(newfd == -1) 169 | continue; 170 | 171 | 172 | pthread_mutex_lock(&pReactor->m_cli_mutex); 173 | pReactor->m_fds.insert(newfd); 174 | pthread_mutex_unlock(&pReactor->m_cli_mutex); 175 | 176 | std::cout << "new client connected: " << std::endl; 177 | 178 | 179 | /* 将新socket设置为non-blocking */ 180 | int oldflag = fcntl(newfd, F_GETFL, 0); 181 | int newflag = oldflag | O_NONBLOCK; 182 | if(fcntl(newfd, F_SETFL, newflag) == -1) 183 | { 184 | std::cout << "fcntl error, oldflag = " << oldflag << ", newflag = " << newflag << std::endl; 185 | continue; 186 | } 187 | 188 | struct epoll_event e; 189 | memset(&e, 0, sizeof(e)); 190 | e.events = EPOLLIN | EPOLLRDHUP | EPOLLET; 191 | e.data.fd = newfd; 192 | /* 添加进epoll的兴趣列表 */ 193 | if(epoll_ctl(pReactor->m_epollfd, EPOLL_CTL_ADD, newfd, &e) == -1) 194 | { 195 | std::cout << "epoll_ctl error, fd = " << newfd << std::endl; 196 | } 197 | } 198 | 199 | return NULL; 200 | } 201 | 202 | void* MyReactor::worker_thread_proc(void* args) 203 | { 204 | ARG *arg = (ARG*)args; 205 | MyReactor* pReactor = arg->pThis; 206 | 207 | while(!pReactor->m_bStop) 208 | { 209 | int clientfd; 210 | pthread_mutex_lock(&pReactor->m_client_mutex); 211 | /* 注意!要用while循环等待 */ 212 | while(pReactor->m_clientlist.empty()) 213 | pthread_cond_wait(&pReactor->m_client_cond, &pReactor->m_client_mutex); 214 | 215 | /* 取出客户套接字 */ 216 | clientfd = pReactor->m_clientlist.front(); 217 | pReactor->m_clientlist.pop_front(); 218 | pthread_mutex_unlock(&pReactor->m_client_mutex); 219 | 220 | std::cout << std::endl; 221 | 222 | 223 | std::string strclientmsg; 224 | char buff[256]; 225 | bool bError = false; 226 | while(1) 227 | { 228 | memset(buff, 0, sizeof(buff)); 229 | int nRecv = recv(clientfd, buff, 256, 0); 230 | if(nRecv == -1) 231 | { 232 | if(errno == EWOULDBLOCK) 233 | break; 234 | else 235 | { 236 | std::cout << "recv error, client disconnected, fd = " << clientfd << std::endl; 237 | pReactor->close_client(clientfd); 238 | bError = true; 239 | break; 240 | } 241 | } 242 | /* 对端关闭了socket,这端也关闭 */ 243 | else if(nRecv == 0) 244 | { 245 | pthread_mutex_lock(&pReactor->m_cli_mutex); 246 | pReactor->m_fds.erase(clientfd); 247 | pthread_mutex_unlock(&pReactor->m_cli_mutex); 248 | 249 | 250 | std::cout << "peer clised, client disconnected, fd = " << clientfd << std::endl; 251 | pReactor->close_client(clientfd); 252 | bError = true; 253 | break; 254 | } 255 | 256 | strclientmsg += buff; 257 | } 258 | 259 | /* 如果出错了就不必往下执行了 */ 260 | if(bError) 261 | { 262 | continue; 263 | } 264 | 265 | std::cout << "client msg: " << strclientmsg; 266 | 267 | /* 将消息加上时间戳 */ 268 | time_t now = time(NULL); 269 | struct tm* nowstr = localtime(&now); 270 | std::ostringstream ostimestr; 271 | ostimestr << "[" << nowstr->tm_year + 1900 << "-" 272 | << std::setw(2) << std::setfill('0') << nowstr->tm_mon + 1 << "-" 273 | << std::setw(2) << std::setfill('0') << nowstr->tm_mday << " " 274 | << std::setw(2) << std::setfill('0') << nowstr->tm_hour << ":" 275 | << std::setw(2) << std::setfill('0') << nowstr->tm_min << ":" 276 | /* << std::setw(2) << std::setfill('0') << nowstr->tm_sec << "]server reply: "; */ 277 | << std::setw(2) << std::setfill('0') << nowstr->tm_sec << " client"<< clientfd << " :"; 278 | 279 | strclientmsg.insert(0, ostimestr.str()); 280 | 281 | 282 | pReactor->m_msgs.push_back(strclientmsg); 283 | pthread_cond_signal(&pReactor->m_send_cond); 284 | 285 | } 286 | return NULL; 287 | } 288 | 289 | 290 | void* MyReactor::send_thread_proc(void *args) 291 | { 292 | ARG *arg = (ARG*)args; 293 | MyReactor* pReactor = arg->pThis; 294 | 295 | while(!pReactor->m_bStop) 296 | { 297 | std::string strclientmsg; 298 | 299 | pthread_mutex_lock(&pReactor->m_send_mutex); 300 | /* 注意!要用while循环等待 */ 301 | while(pReactor->m_msgs.empty()) 302 | pthread_cond_wait(&pReactor->m_send_cond, &pReactor->m_send_mutex); 303 | 304 | strclientmsg = pReactor->m_msgs.front(); 305 | pReactor->m_msgs.pop_front(); 306 | pthread_mutex_unlock(&pReactor->m_send_mutex); 307 | 308 | std::cout << std::endl; 309 | 310 | 311 | while(1) 312 | { 313 | int nSend; 314 | int clientfd; 315 | for(auto it = pReactor->m_fds.begin(); it != pReactor->m_fds.end(); it++) 316 | { 317 | clientfd = *it; 318 | nSend = send(clientfd, strclientmsg.c_str(), strclientmsg.length(), 0); 319 | if(nSend == -1) 320 | { 321 | if(errno == EWOULDBLOCK) 322 | { 323 | sleep(10); 324 | continue; 325 | } 326 | else 327 | { 328 | std::cout << "send error, fd = " << clientfd << std::endl; 329 | pReactor->close_client(clientfd); 330 | break; 331 | } 332 | } 333 | } 334 | 335 | std::cout << "send: " << strclientmsg << std::endl; 336 | /* 发送完把缓冲区清干净 */ 337 | /* strclientmsg.erase(0, nSend); */ 338 | strclientmsg.clear(); 339 | 340 | if(strclientmsg.empty()) 341 | break; 342 | } 343 | } 344 | 345 | return NULL; 346 | } 347 | -------------------------------------------------------------------------------- /dayFour/MyReactor.h: -------------------------------------------------------------------------------- 1 | #ifndef __MYREACTOR_H 2 | #define __MYREACTOR_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include //for htonl() and htons() 11 | #include 12 | #include 13 | #include 14 | #include //for signal() 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include //for std::setw()/setfill() 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | 31 | 32 | #define WORKER_THREAD_NUM 5 33 | 34 | 35 | class MyReactor{ 36 | public: 37 | MyReactor(); 38 | ~MyReactor(); 39 | 40 | /* 初始化socket和线程,供应用程序调用 */ 41 | bool init(const char *ip, short nport); 42 | /* static void *accept_thread_proc(void* args); */ 43 | /* static void *worker_thread_proc(void* args); */ 44 | 45 | 46 | bool uninit(); 47 | 48 | bool close_client(int clientfd); 49 | 50 | static void* main_loop(void* loop); 51 | 52 | private: 53 | /* 见条款6,阻止有人调用复制构造函数和赋值运算符构造函数 */ 54 | MyReactor(const MyReactor& rhs); 55 | MyReactor& operator = (const MyReactor& rhs); 56 | 57 | static void *accept_thread_proc(void* args); 58 | static void *worker_thread_proc(void* args); 59 | 60 | static void *send_thread_proc(void* args); 61 | 62 | bool create_server_listener(const char* ip, short port); 63 | 64 | 65 | private: 66 | /* 服务器端的socket */ 67 | int m_listenfd = 0; 68 | /* 让线程可以修改它 */ 69 | int m_epollfd = 0; 70 | /* 线程ID */ 71 | pthread_t m_accept_threadid; 72 | pthread_t m_threadid[WORKER_THREAD_NUM]; 73 | 74 | pthread_t m_send_threadid; 75 | 76 | /* 接受客户的信号量 */ 77 | pthread_mutex_t m_accept_mutex = PTHREAD_MUTEX_INITIALIZER; 78 | /* 有新连接的条件变量 */ 79 | pthread_cond_t m_accept_cond = PTHREAD_COND_INITIALIZER; 80 | /* 添加、取出客户链表的信号量 */ 81 | pthread_mutex_t m_client_mutex = PTHREAD_MUTEX_INITIALIZER; 82 | /* 通知工作线程有客户消息的条件变量 */ 83 | pthread_cond_t m_client_cond = PTHREAD_COND_INITIALIZER; 84 | 85 | pthread_mutex_t m_send_mutex = PTHREAD_MUTEX_INITIALIZER; 86 | pthread_cond_t m_send_cond = PTHREAD_COND_INITIALIZER; 87 | std::deque m_msgs; 88 | 89 | pthread_mutex_t m_cli_mutex = PTHREAD_MUTEX_INITIALIZER; 90 | pthread_cond_t m_cli_cond = PTHREAD_COND_INITIALIZER; 91 | /* std::vector m_fds; */ 92 | std::set m_fds; 93 | 94 | 95 | /* 存储连接客户的链表 */ 96 | std::list m_clientlist; 97 | 98 | 99 | /* 决定主线程、accept线程、工作线程是否继续迭代 */ 100 | bool m_bStop = false; 101 | }; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /dayFour/README.md: -------------------------------------------------------------------------------- 1 | ## dayFour 2 | 今天把注意力放在服务器,之前写的服务器有点看不过去,现在写一个reactor模式的聊天服务器,这样服务器的并发性能更好 3 | -------------------------------------------------------------------------------- /dayFour/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MyReactor.h" 2 | 3 | MyReactor g_reactor; 4 | 5 | 6 | void prog_exit(int signo) 7 | { 8 | std::cout << "program recv signal " << signo << " to exit." << std::endl; 9 | 10 | g_reactor.uninit(); 11 | } 12 | 13 | void daemon_run() 14 | { 15 | int pid; 16 | signal(SIGCHLD, SIG_IGN); 17 | //1)在父进程中,fork返回新创建子进程的进程ID; 18 | //2)在子进程中,fork返回0; 19 | //3)如果出现错误,fork返回一个负值; 20 | pid = fork(); 21 | if (pid < 0) 22 | { 23 | std:: cout << "fork error" << std::endl; 24 | exit(-1); 25 | } 26 | //父进程退出,子进程独立运行 27 | else if (pid > 0) { 28 | exit(0); 29 | } 30 | //之前parent和child运行在同一个session里,parent是会话(session)的领头进程, 31 | //parent进程作为会话的领头进程,如果exit结束执行的话,那么子进程会成为孤儿进程,并被init收养。 32 | //执行setsid()之后,child将重新获得一个新的会话(session)id。 33 | //这时parent退出之后,将不会影响到child了。 34 | setsid(); 35 | int fd; 36 | fd = open("/dev/null", O_RDWR, 0); 37 | if (fd != -1) 38 | { 39 | dup2(fd, STDIN_FILENO); 40 | dup2(fd, STDOUT_FILENO); 41 | dup2(fd, STDERR_FILENO); 42 | } 43 | if (fd > 2) 44 | close(fd); 45 | } 46 | 47 | 48 | int main(int argc, char* argv[]) 49 | { 50 | //设置信号处理 51 | signal(SIGCHLD, SIG_DFL); 52 | signal(SIGPIPE, SIG_IGN); 53 | signal(SIGINT, prog_exit); 54 | signal(SIGKILL, prog_exit); 55 | signal(SIGTERM, prog_exit); 56 | 57 | short port = 0; 58 | int ch; 59 | bool bdaemon = false; 60 | while ((ch = getopt(argc, argv, "p:d")) != -1) 61 | { 62 | switch (ch) 63 | { 64 | case 'd': 65 | bdaemon = true; 66 | break; 67 | case 'p': 68 | port = atol(optarg); 69 | break; 70 | } 71 | } 72 | 73 | if (bdaemon) 74 | daemon_run(); 75 | 76 | 77 | if (port == 0) 78 | port = 12345; 79 | 80 | if (!g_reactor.init("0.0.0.0", 12345)) 81 | return -1; 82 | 83 | 84 | g_reactor.main_loop(&g_reactor); 85 | 86 | std::cout << "main exit" << std::endl; 87 | 88 | return 0; 89 | } 90 | 91 | 92 | -------------------------------------------------------------------------------- /dayOne/Makefile: -------------------------------------------------------------------------------- 1 | target: 2 | gcc server.c -o server 3 | gcc client.c -o client 4 | 5 | clean: 6 | rm -rf server client 7 | -------------------------------------------------------------------------------- /dayOne/README.md: -------------------------------------------------------------------------------- 1 | ## dayOne 2 | 1. 首先实现一个简单的聊天室服务器,基于之前所学的Linux网络编程的知识 3 | 2. 客户端可以自己实现,也可以直接使用nc命令或telnet命令来充当客户端 4 | -------------------------------------------------------------------------------- /dayOne/client.c: -------------------------------------------------------------------------------- 1 | //---------------------------------客户端client.c---------------------------------------// 2 | #include 3 | #include //定义数据结构sockaddr_in 4 | #include //定义socket函数以及数据结构 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | struct sockaddr_in clientaddr; //定义地址结构 16 | pid_t pid; 17 | int clientfd, sendbytes, recvbytes; 18 | struct hostent *host; //主机信息数据结构 19 | char *buf, *buf_read; 20 | if (argc < 4) 21 | { 22 | printf("wrong usage"); 23 | printf("%s host port name\n", argv[0]); 24 | exit(1); 25 | } 26 | host = gethostbyname(argv[1]); 27 | if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 28 | { 29 | perror("fail to create socket"); 30 | exit(1); 31 | } 32 | bzero(&clientaddr, sizeof(clientaddr)); 33 | clientaddr.sin_family = AF_INET; 34 | clientaddr.sin_port = htons((uint16_t)atoi(argv[2])); 35 | clientaddr.sin_addr = *((struct in_addr *)host->h_addr); 36 | //客户端连接服务端 37 | if (connect(clientfd, (struct sockaddr *)&clientaddr, sizeof(struct sockaddr)) == -1) 38 | { 39 | perror("fail to connect"); 40 | exit(1); 41 | } 42 | buf = (char *)malloc(120); 43 | memset(buf, 0, 120); 44 | buf_read = (char *)malloc(100); 45 | 46 | if (recv(clientfd, buf, 100, 0) == -1) 47 | { 48 | perror("fail to recv"); 49 | exit(1); 50 | } 51 | printf("\n%s\n", buf); 52 | pid = fork(); 53 | while (1) 54 | { 55 | if (pid > 0) 56 | { 57 | //父进程发送消息 58 | strcpy(buf, argv[3]); 59 | strcat(buf, ":"); 60 | memset(buf_read, 0, 100); 61 | fgets(buf_read, 100, stdin); 62 | strcat(buf_read, " "); 63 | strncat(buf, buf_read, strlen(buf_read) - 1); 64 | if ((sendbytes = send(clientfd, buf, strlen(buf), 0)) == -1) 65 | { 66 | perror("fail to send"); 67 | exit(1); 68 | } 69 | } 70 | else if (pid == 0) 71 | { 72 | //子进程接受消息 73 | memset(buf, 0, 100); 74 | if (recv(clientfd, buf, 100, 0) <= 0) 75 | { 76 | perror("fail to recv"); 77 | close(clientfd); 78 | raise(SIGSTOP); 79 | exit(1); 80 | } 81 | printf("%s\n", buf); 82 | } 83 | else 84 | perror("fork error"); 85 | } 86 | close(clientfd); 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /dayOne/server.c: -------------------------------------------------------------------------------- 1 | //-------------------------服务器端server.c-------------------------------// 2 | #include 3 | #include 4 | #include //数据类型定义 5 | #include //文件属性 6 | #include //定义数据结构sockaddr_in 7 | #include //提供socket函数和数据结构 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include //共享内存 15 | #include 16 | #include 17 | 18 | #define PERM S_IRUSR | S_IWUSR //用户读写 19 | #define MYPORT 12345 //通信端口 20 | #define BACKLOG 10 //定义服务器段可以连接的最大客户数 21 | #define WELCOME "|---------------Welcome to the chat room!----------------|"//当客户端连接服务端时,向客户端发送此字符串 22 | 23 | //得到当前系统的时间 24 | void get_cur_time(char *time_str) 25 | { 26 | struct timeval now; 27 | gettimeofday(&now, NULL); 28 | strcpy(time_str, ctime(&now.tv_sec)); 29 | } 30 | 31 | //创建共享存储区 32 | int shm_create() 33 | { 34 | int shmid; 35 | if ((shmid = shmget(IPC_PRIVATE, 1024, PERM)) == -1) 36 | { 37 | fprintf(stderr, "Create Share Memory Error:%s\n\a", strerror(errno)); 38 | exit(1); 39 | } 40 | return shmid; 41 | } 42 | 43 | //端口绑定函数。创建套接字,并绑定到指定端口 44 | int bindPort(unsigned short int port) 45 | { 46 | int sockfd; 47 | struct sockaddr_in my_addr; 48 | sockfd = socket(AF_INET, SOCK_STREAM, 0); //创建基于流套接字 49 | bzero(&my_addr, sizeof(my_addr)); 50 | my_addr.sin_family = AF_INET; //IPV4协议族 51 | my_addr.sin_port = htons(port); //转换端口为网络字节序 52 | my_addr.sin_addr.s_addr = INADDR_ANY; 53 | 54 | if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1) 55 | { 56 | perror("fail to bind"); 57 | exit(1); 58 | } 59 | 60 | printf("bind success!\n"); 61 | return sockfd; 62 | } 63 | 64 | int main(int argc, char *argv[]) 65 | { 66 | int sockfd, clientfd; //监听套接字、客户套接字 67 | int sin_size, recvbytes; 68 | 69 | pid_t pid, ppid; //定义父子进程标记 70 | char *buf, *read_addr, *write_addr, *temp, *time_str; //需要用到的缓冲区 71 | struct sockaddr_in their_addr; //定义地址结构 72 | int shmid; 73 | 74 | shmid = shm_create(); //创建共享存储区 75 | 76 | temp = (char *)malloc(255); 77 | time_str = (char *)malloc(50); 78 | sockfd = bindPort(MYPORT); //绑定端口 79 | 80 | get_cur_time(time_str); 81 | printf("Time is : %s\n", time_str); 82 | 83 | if (listen(sockfd, BACKLOG) == -1) 84 | { 85 | //在指定端口上监听 86 | perror("fail to listen"); 87 | exit(1); 88 | } 89 | 90 | printf("listen....\n"); 91 | while (1) 92 | { 93 | //接受一个客户端的连接请求,相当于不限客户数,群发消息 94 | if ((clientfd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) 95 | { 96 | perror("fail to accept"); 97 | exit(1); 98 | } 99 | printf("%d \n", clientfd); 100 | //得到客户端的IP地址输出 101 | char address[20]; 102 | inet_ntop(AF_INET, &their_addr.sin_addr, address, sizeof(address)); 103 | 104 | //printf("accept from %s\n", address); 105 | send(clientfd, WELCOME, strlen(WELCOME), 0); //发送问候信息 106 | buf = (char *)malloc(255); 107 | 108 | ppid = fork(); //创建子进程 109 | if (ppid == 0) //子进程 110 | { 111 | pid = fork(); //子进程创建子进程 112 | while (1) 113 | { 114 | if (pid > 0) 115 | { 116 | //buf = (char *)malloc(255); 117 | //父进程用于接收信息 118 | memset(buf, 0, 255); 119 | printf("OK\n"); 120 | if ((recvbytes = recv(clientfd, buf, 255, 0)) <= 0) 121 | { 122 | perror("fail to recv"); 123 | close(clientfd); 124 | raise(SIGKILL); 125 | exit(1); 126 | } 127 | write_addr = shmat(shmid, 0, 0); //shmat将shmid所代表的全局的共享存储区关联到本进程的进程空间 128 | memset(write_addr, '\0', 1024); 129 | 130 | //把接收到的消息存入共享存储区中 131 | strncpy(write_addr, buf, 1024); 132 | 133 | //把接收到的消息连接此刻的时间字符串输出到标准输出 134 | get_cur_time(time_str); 135 | strcat(buf, time_str); 136 | printf("%s\n", buf); 137 | } 138 | else if (pid == 0) 139 | { 140 | //子进程的子进程用于发送消息 141 | sleep(1); //子进程先等待父进程把接收到的信息存入共享存储区 142 | read_addr = shmat(shmid, 0, 0); //读取共享存储区的内容 143 | 144 | //temp存储上次读取过的内容,每次先判断是否已经读取过该消息 145 | if (strcmp(temp, read_addr) != 0) 146 | { 147 | strcpy(temp, read_addr); //更新temp,表示已经读取过该消息 148 | 149 | get_cur_time(time_str); 150 | strcat(read_addr, " "); 151 | strcat(read_addr, time_str); 152 | if (send(clientfd, read_addr, strlen(read_addr), 0) == -1) 153 | { 154 | perror("fail to send"); 155 | exit(1); 156 | } 157 | memset(read_addr, '\0', 1024); 158 | strcpy(read_addr, temp); 159 | } 160 | } 161 | else 162 | perror("fail to fork"); 163 | } 164 | } 165 | } 166 | printf("------------------------------------\n"); 167 | free(buf); 168 | close(sockfd); 169 | close(clientfd); 170 | return 0; 171 | } 172 | -------------------------------------------------------------------------------- /daySix/Chat+mysql/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ -g -Wall -std=c++11 -I /usr/include/mysql/ -o main main.cpp MyReactor.cpp -I ../../dep -pthread -lmysqlclient 3 | 4 | clean: 5 | rm -rf main 6 | -------------------------------------------------------------------------------- /daySix/Chat+mysql/MyReactor.cpp: -------------------------------------------------------------------------------- 1 | #include "MyReactor.h" 2 | 3 | #include "spdlog/sinks/daily_file_sink.h" 4 | #include "spdlog/sinks/basic_file_sink.h" 5 | auto my_logger = spdlog::stdout_color_mt("my_logger"); 6 | 7 | MyReactor::MyReactor() 8 | { 9 | } 10 | 11 | MyReactor::~MyReactor() 12 | { 13 | } 14 | 15 | struct ARG 16 | { 17 | MyReactor* pThis; 18 | }; 19 | 20 | bool MyReactor::init(const char* ip, short nport) 21 | { 22 | //连接数据库 23 | int ret = connect(); 24 | if(ret == -1) 25 | { 26 | my_logger->error("mysql connection failed"); 27 | } 28 | 29 | 30 | if(!create_server_listener(ip, nport)) 31 | { 32 | my_logger->error("Unable to bind: {0}:{1}.", ip, nport); 33 | return false; 34 | } 35 | 36 | ARG *arg = new ARG(); 37 | arg->pThis = this; 38 | 39 | pthread_create(&m_accept_threadid, NULL, accept_thread_proc, (void*)arg); 40 | 41 | pthread_create(&m_send_threadid, NULL, send_thread_proc, (void*)arg); 42 | 43 | for(int i = 0; i < WORKER_THREAD_NUM; i++) 44 | { 45 | pthread_create(&m_threadid[i], NULL, worker_thread_proc, (void*)arg); 46 | } 47 | 48 | return true; 49 | } 50 | 51 | 52 | bool MyReactor::uninit() 53 | { 54 | m_bStop = true; 55 | 56 | /* 将读端和写端都关闭 */ 57 | shutdown(m_listenfd, SHUT_RDWR); 58 | close(m_listenfd); 59 | close(m_epollfd); 60 | 61 | mysql_close(mysql); 62 | 63 | return true; 64 | } 65 | 66 | 67 | void* MyReactor::main_loop(void *p) 68 | { 69 | my_logger->info("main thread id = {}", pthread_self()); 70 | 71 | MyReactor* pReactor = static_cast(p); 72 | 73 | while(!pReactor->m_bStop) 74 | { 75 | struct epoll_event ev[1024]; 76 | int n = epoll_wait(pReactor->m_epollfd, ev, 1024, 10); 77 | if(n == 0) 78 | continue; 79 | else if(n < 0) 80 | { 81 | my_logger->error("epoll_wait error"); 82 | continue; 83 | } 84 | 85 | int m = std::min(n, 1024); 86 | for(int i = 0; i < m; i++) 87 | { 88 | /* 有新连接 */ 89 | if(ev[i].data.fd == pReactor->m_listenfd) 90 | pthread_cond_signal(&pReactor->m_accept_cond); 91 | /* 有数据 */ 92 | else 93 | { 94 | pthread_mutex_lock(&pReactor->m_client_mutex); 95 | pReactor->m_clientlist.push_back(ev[i].data.fd); 96 | pthread_mutex_unlock(&pReactor->m_client_mutex); 97 | pthread_cond_signal(&pReactor->m_client_cond); 98 | } 99 | } 100 | } 101 | 102 | my_logger->info("main loop exit ..."); 103 | return NULL; 104 | } 105 | 106 | 107 | bool MyReactor::close_client(int clientfd) 108 | { 109 | if(epoll_ctl(m_epollfd, EPOLL_CTL_DEL, clientfd, NULL) == -1) 110 | { 111 | my_logger->warn("release client socket failed as call epoll_ctl fail"); 112 | } 113 | 114 | close(clientfd); 115 | return true; 116 | } 117 | 118 | 119 | bool MyReactor::create_server_listener(const char* ip, short port) 120 | { 121 | m_listenfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); 122 | if(m_listenfd == -1) 123 | { 124 | my_logger->error("fail to create a socket"); 125 | return false; 126 | } 127 | 128 | int on = 1; 129 | setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); 130 | setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)); 131 | 132 | struct sockaddr_in servaddr; 133 | memset(&servaddr, 0, sizeof(servaddr)); 134 | servaddr.sin_family = AF_INET; 135 | servaddr.sin_addr.s_addr = inet_addr(ip); 136 | servaddr.sin_port = htons(port); 137 | 138 | if(bind(m_listenfd, (sockaddr *)&servaddr, sizeof(servaddr)) == -1) 139 | return false; 140 | 141 | if(listen(m_listenfd, 50) == -1) 142 | return false; 143 | 144 | m_epollfd = epoll_create(1); 145 | if(m_epollfd == -1) 146 | return false; 147 | 148 | struct epoll_event e; 149 | memset(&e, 0, sizeof(e)); 150 | e.events = EPOLLIN | EPOLLRDHUP; 151 | e.data.fd = m_listenfd; 152 | if(epoll_ctl(m_epollfd, EPOLL_CTL_ADD, m_listenfd, &e) == -1) 153 | return false; 154 | 155 | return true; 156 | } 157 | 158 | 159 | void* MyReactor::accept_thread_proc(void* args) 160 | { 161 | ARG *arg = (ARG*)args; 162 | MyReactor* pReactor = arg->pThis; 163 | 164 | while(!pReactor->m_bStop) 165 | { 166 | pthread_mutex_lock(&pReactor->m_accept_mutex); 167 | pthread_cond_wait(&pReactor->m_accept_cond, &pReactor->m_accept_mutex); 168 | 169 | struct sockaddr_in clientaddr; 170 | socklen_t addrlen; 171 | int newfd = accept(pReactor->m_listenfd, (struct sockaddr *)&clientaddr, &addrlen); 172 | pthread_mutex_unlock(&pReactor->m_accept_mutex); 173 | if(newfd == -1) 174 | continue; 175 | 176 | 177 | pthread_mutex_lock(&pReactor->m_cli_mutex); 178 | pReactor->m_fds.insert(newfd); 179 | pthread_mutex_unlock(&pReactor->m_cli_mutex); 180 | 181 | my_logger->info("new client connected: "); 182 | 183 | /* 将新socket设置为non-blocking */ 184 | int oldflag = fcntl(newfd, F_GETFL, 0); 185 | int newflag = oldflag | O_NONBLOCK; 186 | if(fcntl(newfd, F_SETFL, newflag) == -1) 187 | { 188 | my_logger->error("fcntl error, oldflag = {0}, newflag = {1}", oldflag, newflag); 189 | continue; 190 | } 191 | 192 | struct epoll_event e; 193 | memset(&e, 0, sizeof(e)); 194 | e.events = EPOLLIN | EPOLLRDHUP | EPOLLET; 195 | e.data.fd = newfd; 196 | /* 添加进epoll的兴趣列表 */ 197 | if(epoll_ctl(pReactor->m_epollfd, EPOLL_CTL_ADD, newfd, &e) == -1) 198 | { 199 | my_logger->error("epoll_ctl error, fd = {}", newfd); 200 | } 201 | } 202 | 203 | return NULL; 204 | } 205 | 206 | void* MyReactor::worker_thread_proc(void* args) 207 | { 208 | ARG *arg = (ARG*)args; 209 | MyReactor* pReactor = arg->pThis; 210 | 211 | while(!pReactor->m_bStop) 212 | { 213 | int clientfd; 214 | pthread_mutex_lock(&pReactor->m_client_mutex); 215 | /* 注意!要用while循环等待 */ 216 | while(pReactor->m_clientlist.empty()) 217 | pthread_cond_wait(&pReactor->m_client_cond, &pReactor->m_client_mutex); 218 | 219 | /* 取出客户套接字 */ 220 | clientfd = pReactor->m_clientlist.front(); 221 | pReactor->m_clientlist.pop_front(); 222 | pthread_mutex_unlock(&pReactor->m_client_mutex); 223 | 224 | std::cout << std::endl; 225 | 226 | time_t now = time(NULL); 227 | struct tm* nowstr = localtime(&now); 228 | std::ostringstream ostimestr; 229 | 230 | std::string strclientmsg; 231 | char buff[256]; 232 | bool bError = false; 233 | while(1) 234 | { 235 | memset(buff, 0, sizeof(buff)); 236 | int nRecv = recv(clientfd, buff, 256, 0); 237 | 238 | if(nRecv == -1) 239 | { 240 | if(errno == EWOULDBLOCK) 241 | break; 242 | else 243 | { 244 | my_logger->error("recv error, client disconnected, fd = {}", clientfd); 245 | pReactor->close_client(clientfd); 246 | bError = true; 247 | break; 248 | } 249 | } 250 | /* 对端关闭了socket,这端也关闭 */ 251 | else if(nRecv == 0) 252 | { 253 | /* 将该客户从客户列表中删除 */ 254 | pthread_mutex_lock(&pReactor->m_cli_mutex); 255 | pReactor->m_fds.erase(clientfd); 256 | pthread_mutex_unlock(&pReactor->m_cli_mutex); 257 | 258 | my_logger->info("peer closed, client disconnected, fd = {}", clientfd); 259 | pReactor->close_client(clientfd); 260 | bError = true; 261 | break; 262 | } 263 | 264 | //注册 265 | if(buff[0] == REGISTER) 266 | { 267 | std::string rec(buff); 268 | auto it = rec.find('\t'); 269 | const char *name = rec.substr(1, it-1).c_str(); 270 | const char *password = rec.substr(it+1, rec.size()-1).c_str(); 271 | 272 | //std::cout << name << '\t' << password << std::endl; 273 | char query[100]; 274 | sprintf(query, "select password from UserInfo where username = '%s'", name); 275 | int ret = pReactor->sqlQuery(query); 276 | pReactor->res_ptr = mysql_store_result(pReactor->mysql); //即使不需要返回值也要这样,否则会出错 277 | if(ret == -1) 278 | { 279 | strclientmsg += "The name has been registered"; 280 | } 281 | else 282 | { 283 | memset(query, 0, sizeof(query)); 284 | sprintf(query, "insert into UserInfo values('%s', '%s')", name, password); 285 | ret = pReactor->sqlQuery(query); 286 | if(ret == -1) 287 | { 288 | strclientmsg += "The name has been registered"; 289 | my_logger->error("insert error {}", mysql_error(pReactor->mysql)); 290 | } 291 | else 292 | { 293 | //注册成功 294 | //新建一个用户表,用于保存用户信息 295 | memset(query, 0, sizeof(query)); 296 | sprintf(query, "create table %s (friends char(30));", name); 297 | pReactor->sqlQuery(query); 298 | //把自己加入到好友表中 299 | memset(query, 0, sizeof(query)); 300 | sprintf(query, "insert into %s values('%s')", name, name); 301 | pReactor->sqlQuery(query); 302 | 303 | strclientmsg += "register success"; 304 | continue; 305 | if(mysql_errno(pReactor->mysql)) 306 | { 307 | my_logger->error("retrive error {}", mysql_error(pReactor->mysql)); 308 | } 309 | } 310 | } 311 | mysql_free_result(pReactor->res_ptr); 312 | } 313 | //登录 314 | else if(buff[0] == LOGIN) 315 | { 316 | std::string rec(buff); 317 | auto it = rec.find('\t'); 318 | const char *name = rec.substr(1, it-1).c_str(); 319 | const char *password = rec.substr(it+1, rec.size()-1).c_str(); 320 | 321 | char query[100]; 322 | sprintf(query, "select password from UserInfo where username = '%s'", name); 323 | int ret = pReactor->sqlQuery(query); 324 | /* std::cout << "ret = " << ret << std::endl; */ 325 | if(ret == -1) 326 | { 327 | my_logger->error("select error {}", mysql_error(pReactor->mysql)); 328 | } 329 | else 330 | { 331 | pReactor->res_ptr = mysql_store_result(pReactor->mysql); 332 | if(pReactor->res_ptr) 333 | { 334 | pReactor->sqlrow = mysql_fetch_row(pReactor->res_ptr); 335 | /* std::cout << pReactor->sqlrow << std::endl; */ 336 | if(pReactor->sqlrow) 337 | { 338 | if(strcmp(pReactor->sqlrow[0], password) == 0) 339 | { 340 | strclientmsg += "LOG IN SUCCESS"; 341 | //登录成功 342 | continue; 343 | } 344 | else 345 | { 346 | strclientmsg += "password is wrong"; 347 | } 348 | if(mysql_errno(pReactor->mysql)) 349 | { 350 | my_logger->error("Retrive error {}", mysql_error(pReactor->mysql)); 351 | } 352 | 353 | } 354 | else 355 | { 356 | strclientmsg += "You have to register first"; 357 | } 358 | } 359 | mysql_free_result(pReactor->res_ptr); 360 | } 361 | } 362 | //聊天信息 363 | else if(buff[0] == MESSAGE) 364 | { 365 | strclientmsg += buff; 366 | } 367 | // TODO:添加好友消息 368 | else if(buff[0] == ADDFRIEND) 369 | { 370 | 371 | } 372 | } 373 | 374 | /* 如果出错了就不必往下执行了 */ 375 | if(bError) 376 | { 377 | continue; 378 | } 379 | 380 | my_logger->info("client msg: {}", strclientmsg); 381 | 382 | if(strclientmsg[0] == MESSAGE) 383 | { 384 | strclientmsg.erase(0, 1); //将命令标识符去掉 385 | /* 将消息加上时间戳 */ 386 | ostimestr << "[" << nowstr->tm_year + 1900 << "-" 387 | << std::setw(2) << std::setfill('0') << nowstr->tm_mon + 1 << "-" 388 | << std::setw(2) << std::setfill('0') << nowstr->tm_mday << " " 389 | << std::setw(2) << std::setfill('0') << nowstr->tm_hour << ":" 390 | << std::setw(2) << std::setfill('0') << nowstr->tm_min << ":" 391 | << std::setw(2) << std::setfill('0') << nowstr->tm_sec << " ] "; 392 | 393 | strclientmsg.insert(0, ostimestr.str()); 394 | } 395 | else 396 | { 397 | send(clientfd, strclientmsg.c_str(), strclientmsg.length(), 0); 398 | continue; 399 | } 400 | 401 | /* 将消息交给发送消息的线程 */ 402 | pReactor->m_msgs.push_back(strclientmsg); 403 | pthread_cond_signal(&pReactor->m_send_cond); 404 | } 405 | return NULL; 406 | } 407 | 408 | 409 | void* MyReactor::send_thread_proc(void *args) 410 | { 411 | ARG *arg = (ARG*)args; 412 | MyReactor* pReactor = arg->pThis; 413 | 414 | while(!pReactor->m_bStop) 415 | { 416 | std::string strclientmsg; 417 | 418 | pthread_mutex_lock(&pReactor->m_send_mutex); 419 | /* 注意!要用while循环等待 */ 420 | while(pReactor->m_msgs.empty()) 421 | pthread_cond_wait(&pReactor->m_send_cond, &pReactor->m_send_mutex); 422 | 423 | strclientmsg = pReactor->m_msgs.front(); 424 | pReactor->m_msgs.pop_front(); 425 | pthread_mutex_unlock(&pReactor->m_send_mutex); 426 | 427 | std::cout << std::endl; 428 | 429 | 430 | while(1) 431 | { 432 | int nSend; 433 | int clientfd; 434 | //广播消息 435 | for(auto it = pReactor->m_fds.begin(); it != pReactor->m_fds.end(); it++) 436 | { 437 | clientfd = *it; 438 | nSend = send(clientfd, strclientmsg.c_str(), strclientmsg.length(), 0); 439 | if(nSend == -1) 440 | { 441 | if(errno == EWOULDBLOCK) 442 | { 443 | sleep(10); 444 | continue; 445 | } 446 | else 447 | { 448 | my_logger->error("send error, fd = {}", clientfd); 449 | pReactor->close_client(clientfd); 450 | break; 451 | } 452 | } 453 | } 454 | 455 | my_logger->info("send: {}", strclientmsg); 456 | /* 发送完把缓冲区清干净 */ 457 | strclientmsg.clear(); 458 | 459 | if(strclientmsg.empty()) 460 | break; 461 | } 462 | } 463 | 464 | return NULL; 465 | } 466 | 467 | //数据库连接 468 | int MyReactor::connect() 469 | { 470 | mysql = mysql_init(NULL); 471 | if(!mysql) 472 | { 473 | my_logger->error("mysql init falied"); 474 | return -1; 475 | } 476 | 477 | /* root为用户名,liujianhao为密码,test为要连接的database */ 478 | mysql = mysql_real_connect(mysql, "localhost", "root", "liujianhao", "ChatRoom", 0, NULL, 0); 479 | 480 | if(mysql) 481 | { 482 | my_logger->info("MySQL connection success"); 483 | } 484 | else 485 | { 486 | my_logger->warn(" MySQL connection failed"); 487 | } 488 | return 0; 489 | } 490 | 491 | //数据库操作 492 | int MyReactor::sqlQuery(const char* query) 493 | { 494 | int res = mysql_query(mysql, query); 495 | if(res) 496 | { 497 | return -1; 498 | } 499 | return 0; 500 | } 501 | -------------------------------------------------------------------------------- /daySix/Chat+mysql/MyReactor.h: -------------------------------------------------------------------------------- 1 | #ifndef __MYREACTOR_H 2 | #define __MYREACTOR_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include //for htonl() and htons() 11 | #include 12 | #include 13 | #include 14 | #include //for signal() 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include //for std::setw()/setfill() 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include "spdlog/spdlog.h" 31 | #include "spdlog/sinks/stdout_color_sinks.h" 32 | 33 | #include "command.h" 34 | 35 | #include 36 | 37 | #define WORKER_THREAD_NUM 5 38 | 39 | 40 | class MyReactor{ 41 | public: 42 | MyReactor(); 43 | ~MyReactor(); 44 | 45 | /* 初始化socket和线程,供应用程序调用 */ 46 | bool init(const char *ip, short nport); 47 | 48 | bool uninit(); 49 | 50 | bool close_client(int clientfd); 51 | 52 | static void* main_loop(void* loop); 53 | 54 | //数据库操作 55 | int connect(); 56 | int sqlQuery(const char*); 57 | 58 | private: 59 | /* 见条款6,阻止有人调用复制构造函数和赋值运算符构造函数 */ 60 | MyReactor(const MyReactor& rhs); 61 | MyReactor& operator = (const MyReactor& rhs); 62 | 63 | static void *accept_thread_proc(void* args); 64 | static void *worker_thread_proc(void* args); 65 | 66 | static void *send_thread_proc(void* args); 67 | 68 | bool create_server_listener(const char* ip, short port); 69 | 70 | 71 | private: 72 | /* 服务器端的socket */ 73 | int m_listenfd = 0; 74 | /* 让线程可以修改它 */ 75 | int m_epollfd = 0; 76 | /* 线程ID */ 77 | pthread_t m_accept_threadid; 78 | pthread_t m_threadid[WORKER_THREAD_NUM]; 79 | 80 | pthread_t m_send_threadid; 81 | 82 | /* 接受客户的信号量 */ 83 | pthread_mutex_t m_accept_mutex = PTHREAD_MUTEX_INITIALIZER; 84 | /* 有新连接的条件变量 */ 85 | pthread_cond_t m_accept_cond = PTHREAD_COND_INITIALIZER; 86 | /* 添加、取出客户链表的信号量 */ 87 | pthread_mutex_t m_client_mutex = PTHREAD_MUTEX_INITIALIZER; 88 | /* 通知工作线程有客户消息的条件变量 */ 89 | pthread_cond_t m_client_cond = PTHREAD_COND_INITIALIZER; 90 | 91 | pthread_mutex_t m_send_mutex = PTHREAD_MUTEX_INITIALIZER; 92 | pthread_cond_t m_send_cond = PTHREAD_COND_INITIALIZER; 93 | std::deque m_msgs; 94 | 95 | pthread_mutex_t m_cli_mutex = PTHREAD_MUTEX_INITIALIZER; 96 | pthread_cond_t m_cli_cond = PTHREAD_COND_INITIALIZER; 97 | 98 | std::set m_fds; 99 | 100 | /* 存储连接客户的链表,用队列也一样*/ 101 | std::list m_clientlist; 102 | 103 | 104 | /* 决定主线程、accept线程、工作线程是否继续迭代 */ 105 | bool m_bStop = false; 106 | 107 | /* MySQL数据库 */ 108 | MYSQL *mysql; 109 | MYSQL_RES *res_ptr; 110 | MYSQL_ROW sqlrow; 111 | }; 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /daySix/Chat+mysql/command.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMAND_H 2 | #define COMMAND_H 3 | 4 | #define REGISTER '1' 5 | #define LOGIN '2' 6 | #define MESSAGE '3' 7 | #define ADDFRIEND '4' 8 | 9 | #endif // COMMAND_H 10 | -------------------------------------------------------------------------------- /daySix/Chat+mysql/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/daySix/Chat+mysql/main -------------------------------------------------------------------------------- /daySix/Chat+mysql/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MyReactor.h" 2 | 3 | 4 | #include "spdlog/sinks/daily_file_sink.h" 5 | #include "spdlog/sinks/basic_file_sink.h" 6 | auto main_logger = spdlog::stdout_color_mt("main_logger"); 7 | 8 | 9 | MyReactor g_reactor; 10 | 11 | 12 | void prog_exit(int signo) 13 | { 14 | main_logger->info("program recv signal {} to exit.", signo); 15 | g_reactor.uninit(); 16 | } 17 | 18 | void daemon_run() 19 | { 20 | int pid; 21 | signal(SIGCHLD, SIG_IGN); 22 | pid = fork(); 23 | if (pid < 0) 24 | { 25 | main_logger->error("fork error"); 26 | exit(-1); 27 | } 28 | else if (pid > 0) { 29 | exit(0); 30 | } 31 | //之前parent和child运行在同一个session里,parent是会话(session)的领头进程, 32 | //parent进程作为会话的领头进程,如果exit结束执行的话,那么子进程会成为孤儿进程,并被init收养。 33 | //执行setsid()之后,child将重新获得一个新的会话(session)id。 34 | //这时parent退出之后,将不会影响到child了。 35 | setsid(); 36 | int fd; 37 | fd = open("/dev/null", O_RDWR, 0); 38 | if (fd != -1) 39 | { 40 | dup2(fd, STDIN_FILENO); 41 | dup2(fd, STDOUT_FILENO); 42 | dup2(fd, STDERR_FILENO); 43 | } 44 | if (fd > 2) 45 | close(fd); 46 | } 47 | 48 | 49 | int main(int argc, char* argv[]) 50 | { 51 | //设置信号处理 52 | signal(SIGCHLD, SIG_DFL); 53 | signal(SIGPIPE, SIG_IGN); 54 | signal(SIGINT, prog_exit); 55 | signal(SIGKILL, prog_exit); 56 | signal(SIGTERM, prog_exit); 57 | 58 | short port = 0; 59 | int ch; 60 | bool bdaemon = false; 61 | while ((ch = getopt(argc, argv, "p:d")) != -1) 62 | { 63 | switch (ch) 64 | { 65 | case 'd': 66 | bdaemon = true; 67 | break; 68 | case 'p': 69 | port = atol(optarg); 70 | break; 71 | } 72 | } 73 | 74 | if (bdaemon) 75 | daemon_run(); 76 | 77 | 78 | if (port == 0) 79 | port = 12345; 80 | 81 | if (!g_reactor.init("0.0.0.0", 12345)) 82 | return -1; 83 | 84 | 85 | g_reactor.main_loop(&g_reactor); 86 | 87 | main_logger->info("main exit"); 88 | 89 | return 0; 90 | } 91 | 92 | 93 | -------------------------------------------------------------------------------- /daySix/ChatRoom/ChatRoom.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-07-13T15:04:31 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QT += network 9 | 10 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 11 | 12 | TARGET = ChatRoom 13 | TEMPLATE = app 14 | 15 | # The following define makes your compiler emit warnings if you use 16 | # any feature of Qt which as been marked as deprecated (the exact warnings 17 | # depend on your compiler). Please consult the documentation of the 18 | # deprecated API in order to know how to port your code away from it. 19 | DEFINES += QT_DEPRECATED_WARNINGS 20 | 21 | # You can also make your code fail to compile if you use deprecated APIs. 22 | # In order to do so, uncomment the following line. 23 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 24 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 25 | 26 | 27 | SOURCES += main.cpp\ 28 | sign.cpp \ 29 | drawer.cpp \ 30 | tcpclient.cpp \ 31 | addfriends.cpp 32 | 33 | HEADERS += \ 34 | sign.h \ 35 | command.h \ 36 | drawer.h \ 37 | tcpclient.h \ 38 | addfriends.h 39 | 40 | FORMS += 41 | 42 | RESOURCES += \ 43 | images.qrc 44 | -------------------------------------------------------------------------------- /daySix/ChatRoom/ChatRoom.pro.user.0360db3: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {0360db30-20c5-4c1d-9aaf-58d00c53f6cd} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.8.0 MinGW 32bit 63 | Desktop Qt 5.8.0 MinGW 32bit 64 | qt.58.win32_mingw53_kit 65 | 0 66 | 0 67 | 0 68 | 69 | D:/QT/build-ChatRoom-Desktop_Qt_5_8_0_MinGW_32bit-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | false 89 | 90 | 91 | 92 | 2 93 | 构建 94 | 95 | ProjectExplorer.BuildSteps.Build 96 | 97 | 98 | 99 | true 100 | Make 101 | 102 | Qt4ProjectManager.MakeStep 103 | 104 | true 105 | clean 106 | 107 | 108 | 1 109 | 清理 110 | 111 | ProjectExplorer.BuildSteps.Clean 112 | 113 | 2 114 | false 115 | 116 | Debug 117 | 118 | Qt4ProjectManager.Qt4BuildConfiguration 119 | 2 120 | true 121 | 122 | 123 | D:/QT/build-ChatRoom-Desktop_Qt_5_8_0_MinGW_32bit-Release 124 | 125 | 126 | true 127 | qmake 128 | 129 | QtProjectManager.QMakeBuildStep 130 | false 131 | 132 | false 133 | false 134 | false 135 | 136 | 137 | true 138 | Make 139 | 140 | Qt4ProjectManager.MakeStep 141 | 142 | false 143 | 144 | 145 | 146 | 2 147 | 构建 148 | 149 | ProjectExplorer.BuildSteps.Build 150 | 151 | 152 | 153 | true 154 | Make 155 | 156 | Qt4ProjectManager.MakeStep 157 | 158 | true 159 | clean 160 | 161 | 162 | 1 163 | 清理 164 | 165 | ProjectExplorer.BuildSteps.Clean 166 | 167 | 2 168 | false 169 | 170 | Release 171 | 172 | Qt4ProjectManager.Qt4BuildConfiguration 173 | 0 174 | true 175 | 176 | 177 | D:/QT/build-ChatRoom-Desktop_Qt_5_8_0_MinGW_32bit-Profile 178 | 179 | 180 | true 181 | qmake 182 | 183 | QtProjectManager.QMakeBuildStep 184 | true 185 | 186 | false 187 | true 188 | false 189 | 190 | 191 | true 192 | Make 193 | 194 | Qt4ProjectManager.MakeStep 195 | 196 | false 197 | 198 | 199 | 200 | 2 201 | 构建 202 | 203 | ProjectExplorer.BuildSteps.Build 204 | 205 | 206 | 207 | true 208 | Make 209 | 210 | Qt4ProjectManager.MakeStep 211 | 212 | true 213 | clean 214 | 215 | 216 | 1 217 | 清理 218 | 219 | ProjectExplorer.BuildSteps.Clean 220 | 221 | 2 222 | false 223 | 224 | Profile 225 | 226 | Qt4ProjectManager.Qt4BuildConfiguration 227 | 0 228 | true 229 | 230 | 3 231 | 232 | 233 | 0 234 | 部署 235 | 236 | ProjectExplorer.BuildSteps.Deploy 237 | 238 | 1 239 | 在本地部署 240 | 241 | ProjectExplorer.DefaultDeployConfiguration 242 | 243 | 1 244 | 245 | 246 | false 247 | false 248 | 1000 249 | 250 | true 251 | 252 | false 253 | false 254 | false 255 | false 256 | true 257 | 0.01 258 | 10 259 | true 260 | 1 261 | 25 262 | 263 | 1 264 | true 265 | false 266 | true 267 | valgrind 268 | 269 | 0 270 | 1 271 | 2 272 | 3 273 | 4 274 | 5 275 | 6 276 | 7 277 | 8 278 | 9 279 | 10 280 | 11 281 | 12 282 | 13 283 | 14 284 | 285 | 2 286 | 287 | ChatRoom 288 | 289 | Qt4ProjectManager.Qt4RunConfiguration:D:/QT/ChatRoom/ChatRoom.pro 290 | true 291 | 292 | ChatRoom.pro 293 | false 294 | 295 | D:/QT/build-ChatRoom-Desktop_Qt_5_8_0_MinGW_32bit-Debug 296 | 3768 297 | false 298 | true 299 | false 300 | false 301 | true 302 | 303 | 1 304 | 305 | 306 | 307 | ProjectExplorer.Project.TargetCount 308 | 1 309 | 310 | 311 | ProjectExplorer.Project.Updater.FileVersion 312 | 18 313 | 314 | 315 | Version 316 | 18 317 | 318 | 319 | -------------------------------------------------------------------------------- /daySix/ChatRoom/addfriends.cpp: -------------------------------------------------------------------------------- 1 | #include "addfriends.h" 2 | #include "command.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | AddFriends::AddFriends(QWidget *parent) 10 | : QDialog(parent) 11 | { 12 | setWindowTitle(tr("Add Friends")); 13 | resize(200,100); 14 | 15 | nameLabel = new QLabel(tr("Name:")); 16 | nameLineEdit = new QLineEdit(); 17 | enterBtn = new QPushButton("Enter"); 18 | 19 | tcpSocket = new QTcpSocket(this); 20 | 21 | mainLayout = new QGridLayout(this); 22 | mainLayout->addWidget(nameLabel, 0, 0); 23 | mainLayout->addWidget(nameLineEdit, 0, 1); 24 | mainLayout->addWidget(enterBtn, 1, 1); 25 | 26 | //连接服务器 27 | port = 12345; 28 | serverIP = new QHostAddress(); 29 | QString ip = "127.0.0.1"; 30 | serverIP->setAddress(ip); 31 | tcpSocket->connectToHost(*serverIP, port); 32 | 33 | connect(enterBtn, SIGNAL(clicked()), this, SLOT(slotEnter())); 34 | connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReceived())); 35 | } 36 | 37 | 38 | AddFriends::~AddFriends() 39 | { 40 | tcpSocket->disconnectFromHost(); 41 | } 42 | 43 | void AddFriends::slotEnter() 44 | { 45 | if(nameLineEdit->text() == "") 46 | { 47 | QMessageBox::warning(this, tr("Name is empty"), tr("Name is empty")); 48 | return; 49 | } 50 | QString msg = tr(ADDFRIENDS); 51 | msg += nameLineEdit->text(); 52 | tcpSocket->write(msg.toLatin1(), msg.length()); 53 | } 54 | 55 | void AddFriends::dataReceived() 56 | { 57 | QByteArray datagram; 58 | datagram.resize(tcpSocket->bytesAvailable()); 59 | tcpSocket->read(datagram.data(), datagram.size()); 60 | QString msg = datagram.data(); 61 | 62 | //如果登录成功就可以进入主界面 63 | if(msg == "The name is wrong") 64 | { 65 | QMessageBox::warning(this, tr("The name is wrong"), tr("The name is wrong")); 66 | } 67 | else if(msg == "message has been sended") 68 | { 69 | QMessageBox::information(this, tr("message has been sended"), tr("message has been sended")); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /daySix/ChatRoom/addfriends.h: -------------------------------------------------------------------------------- 1 | #ifndef ADDFRIENDS_H 2 | #define ADDFRIENDS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | class AddFriends : public QDialog 14 | { 15 | Q_OBJECT 16 | public: 17 | AddFriends(QWidget *parent = 0); 18 | ~AddFriends(); 19 | 20 | private: 21 | QGridLayout *mainLayout; 22 | QLabel *nameLabel; 23 | QLineEdit *nameLineEdit; 24 | QPushButton *enterBtn; 25 | 26 | int port; 27 | QHostAddress *serverIP; 28 | QTcpSocket *tcpSocket; 29 | 30 | public slots: 31 | void slotEnter(); 32 | void dataReceived(); 33 | }; 34 | 35 | #endif // ADDFRIENDS_H 36 | -------------------------------------------------------------------------------- /daySix/ChatRoom/chatroom.cpp: -------------------------------------------------------------------------------- 1 | #include "chatroom.h" 2 | #include 3 | #include 4 | 5 | ChatRoom::ChatRoom(QWidget *parent,Qt::WindowFlags f) 6 | : QDialog(parent,f) 7 | { 8 | setWindowTitle(tr("TCP Client")); 9 | contentListWidget = new QListWidget; 10 | sendLineEdit = new QLineEdit; 11 | sendBtn = new QPushButton(tr("Send")); 12 | clearBtn = new QPushButton(tr("Clear")); 13 | enterBtn= new QPushButton(tr("Enter Chat Room")); 14 | mainLayout = new QGridLayout(this); 15 | mainLayout->addWidget(contentListWidget,0,0,1,3); 16 | mainLayout->addWidget(sendLineEdit,1,0); 17 | mainLayout->addWidget(sendBtn,1,1); 18 | mainLayout->addWidget(clearBtn,1,2); 19 | mainLayout->addWidget(enterBtn,2,0,1,3); 20 | 21 | 22 | status = false; 23 | //连接服务器 24 | port = 12345; 25 | IP = "172.29.1.82"; 26 | serverIP = new QHostAddress(); 27 | connect(enterBtn, SIGNAL(clicked()), this, SLOT(slotEnter())); 28 | connect(sendBtn, SIGNAL(clicked()), this, SLOT(slotSend())); 29 | connect(clearBtn, SIGNAL(clicked()), this, SLOT(slotClear())); 30 | sendBtn->setEnabled(false); 31 | } 32 | 33 | ChatRoom::~ChatRoom() 34 | { 35 | } 36 | 37 | void ChatRoom::slotEnter() 38 | { 39 | if(!status) 40 | { 41 | /* 完成输入合法性检验 */ 42 | if(!serverIP->setAddress(IP)) 43 | { 44 | QMessageBox::information(this,tr("error"),tr("server ip address error!")); 45 | return; 46 | } 47 | 48 | /* 创建了一个QTcpSocket类对象,并将信号/槽连接起来 */ 49 | tcpSocket = new QTcpSocket(this); 50 | connect(tcpSocket, SIGNAL(connected()), this, SLOT (slotConnected())); 51 | connect(tcpSocket, SIGNAL(disconnected()), this, SLOT (slotDisconnected ())); 52 | connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReceived())); 53 | tcpSocket->connectToHost(*serverIP, port); 54 | status = true; 55 | sendBtn->setEnabled(true); 56 | } 57 | else 58 | { 59 | int length = 0; 60 | QString msg = tr(" :Leave Chat Room"); 61 | if((length = tcpSocket->write(msg.toLatin1(),msg. length()))!=msg. length()) 62 | { 63 | return; 64 | } 65 | tcpSocket->disconnectFromHost(); 66 | status = false; //将status状态复位 67 | } 68 | } 69 | 70 | void ChatRoom::slotConnected() 71 | { 72 | enterBtn->setText(tr("leave")); 73 | int length = 0; 74 | QString msg = tr(" :Enter Chat Room"); 75 | if((length = tcpSocket->write(msg.toLatin1(), msg.length())) != msg.length()) 76 | { 77 | return; 78 | } 79 | } 80 | 81 | void ChatRoom::slotSend() 82 | { 83 | if(sendLineEdit->text() == "") 84 | { 85 | return; 86 | } 87 | QString msg = sendLineEdit->text(); 88 | tcpSocket->write(msg.toLatin1(), msg.length()); 89 | sendLineEdit->clear(); 90 | } 91 | 92 | void ChatRoom::slotDisconnected() 93 | { 94 | sendBtn->setEnabled(false); 95 | enterBtn->setText(tr("Enter Chat Room")); 96 | } 97 | 98 | void ChatRoom::slotClear() 99 | { 100 | contentListWidget->clear(); 101 | } 102 | 103 | void ChatRoom::dataReceived() 104 | { 105 | while(tcpSocket->bytesAvailable()>0) 106 | { 107 | QByteArray datagram; 108 | datagram.resize(tcpSocket->bytesAvailable()); 109 | tcpSocket->read(datagram.data(),datagram.size()); 110 | QString msg=datagram.data(); 111 | contentListWidget->addItem(msg.left(datagram.size())); 112 | contentListWidget->scrollToBottom(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /daySix/ChatRoom/chatroom.h: -------------------------------------------------------------------------------- 1 | #ifndef CHATROOM_H 2 | #define CHATROOM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "command.h" 14 | 15 | class ChatRoom : public QDialog 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | ChatRoom(QWidget *parent = 0,Qt::WindowFlags f=0); 21 | ~ChatRoom(); 22 | 23 | private: 24 | QListWidget *contentListWidget; 25 | QLineEdit *sendLineEdit; 26 | QPushButton *sendBtn; 27 | QPushButton *clearBtn; 28 | QPushButton *enterBtn; 29 | QGridLayout *mainLayout; 30 | bool status; 31 | int port; 32 | QString IP; 33 | QHostAddress *serverIP; 34 | QTcpSocket *tcpSocket; 35 | 36 | public slots: 37 | void slotEnter(); 38 | void slotConnected(); 39 | void slotDisconnected(); 40 | void dataReceived(); 41 | void slotSend(); 42 | void slotClear(); 43 | }; 44 | 45 | 46 | #endif // CHATROOM_H 47 | -------------------------------------------------------------------------------- /daySix/ChatRoom/command.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMAND_H 2 | #define COMMAND_H 3 | 4 | #define REGISTER "1" 5 | #define LOGIN "2" 6 | #define MESSAGE "3" 7 | #define ADDFRIENDS "4" 8 | 9 | #endif // COMMAND_H 10 | -------------------------------------------------------------------------------- /daySix/ChatRoom/drawer.cpp: -------------------------------------------------------------------------------- 1 | #include "drawer.h" 2 | #include 3 | #include 4 | #include 5 | 6 | Drawer::Drawer(QWidget *parent, Qt::WindowFlags f) 7 | :QToolBox(parent, f) 8 | { 9 | setWindowTitle(tr("Chat Room")); 10 | setWindowIcon(QPixmap(":/images/ChatRoom.jpg")); 11 | 12 | addFriendsBtn = new QPushButton(tr("ADD")); 13 | connect(addFriendsBtn, SIGNAL(clicked()), this, SLOT(slotAddFriends())); 14 | 15 | toolBtn1 = new QToolButton; 16 | toolBtn1->setIcon(QPixmap(":/images/liu.png")); 17 | toolBtn1->setIconSize(QPixmap(":/images/liu.png").size()); 18 | toolBtn1->setAutoRaise(true); 19 | toolBtn1->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 20 | connect(toolBtn1, SIGNAL(clicked()), this, SLOT(showChatWidget1())); 21 | 22 | QGroupBox *groupBox = new QGroupBox; 23 | QVBoxLayout *layout = new QVBoxLayout(groupBox); 24 | 25 | layout->setMargin(20); 26 | layout->setAlignment(Qt::AlignLeft); 27 | layout->addWidget(toolBtn1); 28 | layout->addWidget(addFriendsBtn); 29 | layout->addStretch(); //插入一个占位符 30 | this->addItem((QWidget*)groupBox, tr("Member")); 31 | } 32 | 33 | void Drawer::showChatWidget1() 34 | { 35 | chat1 = new TcpClient(); 36 | chat1->username = toolBtn1->text(); 37 | chat1->setWindowTitle(toolBtn1->text()); 38 | chat1->show(); 39 | } 40 | 41 | void Drawer::slotAddFriends() 42 | { 43 | addFriends = new AddFriends(); 44 | addFriends->show(); 45 | } 46 | -------------------------------------------------------------------------------- /daySix/ChatRoom/drawer.h: -------------------------------------------------------------------------------- 1 | #ifndef DRAWER_H 2 | #define DRAWER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tcpclient.h" 8 | #include "addfriends.h" 9 | 10 | class Drawer : public QToolBox 11 | { 12 | Q_OBJECT 13 | public: 14 | Drawer(QWidget *parent = 0, Qt::WindowFlags f = 0); 15 | 16 | QString username; 17 | QToolButton *toolBtn1; 18 | QPushButton *addFriendsBtn; 19 | 20 | private slots: 21 | void showChatWidget1(); 22 | void slotAddFriends(); 23 | 24 | private: 25 | TcpClient *chat1; 26 | AddFriends *addFriends; 27 | }; 28 | 29 | #endif // DRAWER_H 30 | -------------------------------------------------------------------------------- /daySix/ChatRoom/images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/liu.png 4 | images/qq.png 5 | images/Linux.jpg 6 | images/ChatRoom.jpg 7 | 8 | 9 | -------------------------------------------------------------------------------- /daySix/ChatRoom/images/ChatRoom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/daySix/ChatRoom/images/ChatRoom.jpg -------------------------------------------------------------------------------- /daySix/ChatRoom/images/Linux.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/daySix/ChatRoom/images/Linux.jpg -------------------------------------------------------------------------------- /daySix/ChatRoom/images/liu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/daySix/ChatRoom/images/liu.png -------------------------------------------------------------------------------- /daySix/ChatRoom/images/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/daySix/ChatRoom/images/qq.png -------------------------------------------------------------------------------- /daySix/ChatRoom/information.h: -------------------------------------------------------------------------------- 1 | #ifndef INFORMATION_H 2 | #define INFORMATION_H 3 | 4 | #include 5 | 6 | QString username; 7 | 8 | #endif // INFORMATION_H 9 | -------------------------------------------------------------------------------- /daySix/ChatRoom/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sign.h" 2 | #include "drawer.h" 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QApplication a(argc, argv); 9 | 10 | Sign s; 11 | s.show(); 12 | 13 | return a.exec(); 14 | } 15 | -------------------------------------------------------------------------------- /daySix/ChatRoom/sign.cpp: -------------------------------------------------------------------------------- 1 | #include "sign.h" 2 | #include "drawer.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | Sign::Sign(QWidget *parent) 9 | : QDialog(parent) 10 | { 11 | setWindowTitle(tr("Register or Log in")); 12 | resize(500, 350); 13 | contentListWidget = new QListWidget; 14 | registerBtn = new QPushButton(tr("Register")); 15 | LogInBtn = new QPushButton(tr("Log In")); 16 | connectBtn = new QPushButton(tr("Connect")); 17 | nameLabel = new QLabel(tr("Name:")); 18 | passwordLabel = new QLabel(tr("Password:")); 19 | nameLineEdit = new QLineEdit(); 20 | passwordLineEdit = new QLineEdit(); 21 | tcpSocket = new QTcpSocket(this); 22 | 23 | 24 | mainLayout = new QGridLayout(this); 25 | mainLayout->addWidget(contentListWidget, 0, 0, 1, 3); 26 | mainLayout->addWidget(nameLabel, 1, 0); 27 | mainLayout->addWidget(nameLineEdit, 1, 1, 1, 2); 28 | mainLayout->addWidget(passwordLabel, 2, 0); 29 | mainLayout->addWidget(passwordLineEdit, 2, 1, 1, 2); 30 | mainLayout->addWidget(registerBtn, 3, 0); 31 | mainLayout->addWidget(LogInBtn, 3, 1); 32 | mainLayout->addWidget(connectBtn, 3, 2); 33 | 34 | registerBtn->setEnabled(false); 35 | LogInBtn->setEnabled(false); 36 | 37 | connect(connectBtn, SIGNAL(clicked()), this, SLOT(slotConnect())); 38 | connect(registerBtn, SIGNAL(clicked()), this, SLOT(slotRegister())); 39 | connect(LogInBtn, SIGNAL(clicked()), this, SLOT(slotLogIn())); 40 | connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReceived())); 41 | connect(tcpSocket, SIGNAL(connected()), this, SLOT(connected())); 42 | } 43 | 44 | Sign::~Sign() 45 | { 46 | tcpSocket->disconnectFromHost(); 47 | } 48 | 49 | void Sign::slotConnect() 50 | { 51 | if(nameLineEdit->text() == "" || passwordLineEdit->text() == "") 52 | { 53 | QMessageBox::warning(this, tr("error"), tr("Name or Password is empty!")); 54 | return; 55 | } 56 | 57 | //连接服务器 58 | port = 12345; 59 | serverIP = new QHostAddress(); 60 | QString ip = "127.0.0.1"; 61 | serverIP->setAddress(ip); 62 | tcpSocket->connectToHost(*serverIP, port); 63 | } 64 | 65 | void Sign::connected() 66 | { 67 | connectBtn->setEnabled(false); 68 | registerBtn->setEnabled(true); 69 | LogInBtn->setEnabled(true); 70 | } 71 | 72 | 73 | void Sign::slotRegister() 74 | { 75 | QString msg = tr(REGISTER); 76 | username = nameLineEdit->text(); 77 | QString password = passwordLineEdit->text(); 78 | msg += username + '\t' + password; 79 | int length = tcpSocket->write(msg.toLatin1(), msg.length()); 80 | if(length != msg.length()) 81 | { 82 | return; 83 | } 84 | } 85 | 86 | void Sign::slotLogIn() 87 | { 88 | QString msg = tr(LOGIN); 89 | username = nameLineEdit->text(); 90 | QString password = passwordLineEdit->text(); 91 | msg += username + '\t' + password; 92 | int length = tcpSocket->write(msg.toLatin1(), msg.length()); 93 | if(length != msg.length()) 94 | { 95 | return; 96 | } 97 | } 98 | 99 | void Sign::dataReceived() 100 | { 101 | QByteArray datagram; 102 | datagram.resize(tcpSocket->bytesAvailable()); 103 | tcpSocket->read(datagram.data(), datagram.size()); 104 | QString msg = datagram.data(); 105 | contentListWidget->addItem(msg.left(datagram.size())); 106 | contentListWidget->scrollToBottom(); //自动回滚信息 107 | 108 | 109 | //如果登录成功就可以进入主界面 110 | if(msg == "LOG IN SUCCESS") 111 | { 112 | QMessageBox::information(this, tr("log in success"), tr("log in success")); 113 | this->hide(); 114 | 115 | drawer = new Drawer(); 116 | drawer->toolBtn1->setText(username); 117 | drawer->resize(250, 500); 118 | drawer->show(); 119 | } 120 | else if(msg == "REGISTER SUCCESS") 121 | { 122 | QMessageBox::information(this, tr("register success, now you can log in"), tr("register success, now you can log in")); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /daySix/ChatRoom/sign.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGN_H 2 | #define SIGN_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "command.h" 15 | #include "drawer.h" 16 | 17 | class Sign : public QDialog 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | Sign(QWidget *parent = 0); 23 | ~Sign(); 24 | 25 | private: 26 | QListWidget *contentListWidget; 27 | QGridLayout *mainLayout; 28 | QLabel *nameLabel; 29 | QLabel *passwordLabel; 30 | QPushButton *connectBtn; 31 | QLineEdit *nameLineEdit; 32 | QLineEdit *passwordLineEdit; 33 | QPushButton *registerBtn; 34 | QPushButton *LogInBtn; 35 | 36 | int port; 37 | QHostAddress *serverIP; 38 | QTcpSocket *tcpSocket; 39 | 40 | QString username; 41 | 42 | Drawer *drawer; 43 | 44 | public slots: 45 | void slotRegister(); 46 | void slotLogIn(); 47 | void slotConnect(); 48 | void dataReceived(); 49 | void connected(); 50 | }; 51 | 52 | #endif // SIGN_H 53 | -------------------------------------------------------------------------------- /daySix/ChatRoom/tcpclient.cpp: -------------------------------------------------------------------------------- 1 | #include "tcpclient.h" 2 | #include 3 | #include 4 | 5 | TcpClient::TcpClient(QWidget *parent,Qt::WindowFlags f) 6 | : QDialog(parent,f) 7 | { 8 | setWindowTitle(tr("TCP Client")); 9 | resize(500, 300); 10 | contentListWidget = new QListWidget; 11 | sendLineEdit = new QLineEdit; 12 | sendBtn = new QPushButton(tr("Send")); 13 | clearBtn = new QPushButton(tr("Clear")); 14 | mainLayout = new QGridLayout(this); 15 | mainLayout->addWidget(contentListWidget,0,0,1,3); 16 | mainLayout->addWidget(sendLineEdit,1,0); 17 | mainLayout->addWidget(sendBtn,1,1); 18 | mainLayout->addWidget(clearBtn,1,2); 19 | port = 12345; 20 | IP = "127.0.0.1"; 21 | serverIP = new QHostAddress(); 22 | connect(sendBtn,SIGNAL(clicked()),this,SLOT(slotSend())); 23 | connect(clearBtn,SIGNAL(clicked()),this,SLOT(slotClear())); 24 | 25 | if(!serverIP->setAddress(IP)) 26 | { 27 | QMessageBox::information(this,tr("error"),tr("server ip address error!")); 28 | return; 29 | } 30 | /* 创建了一个QTcpSocket类对象,并将信号/槽连接起来 */ 31 | tcpSocket = new QTcpSocket(this); 32 | connect(tcpSocket,SIGNAL(connected()),this,SLOT (slotConnected())); 33 | connect(tcpSocket,SIGNAL(readyRead()),this,SLOT (dataReceived())); 34 | tcpSocket->connectToHost(*serverIP ,port); 35 | } 36 | 37 | TcpClient::~TcpClient() 38 | { 39 | 40 | } 41 | 42 | 43 | void TcpClient::slotConnected() 44 | { 45 | sendBtn->setEnabled(true); 46 | int length=0; 47 | QString msg = username + ": Enter Chat Room"; 48 | if((length = tcpSocket->write(msg.toLatin1(),msg. length())) != msg.length()) 49 | { 50 | return; 51 | } 52 | } 53 | 54 | void TcpClient::slotSend() 55 | { 56 | if(sendLineEdit->text() == "") 57 | { 58 | return; 59 | } 60 | QString msg = username + ": " + sendLineEdit->text(); 61 | tcpSocket->write(msg.toLatin1(), msg.length()); 62 | sendLineEdit->clear(); 63 | } 64 | 65 | void TcpClient::slotClear() 66 | { 67 | contentListWidget->clear(); 68 | } 69 | 70 | void TcpClient::dataReceived() 71 | { 72 | while(tcpSocket->bytesAvailable() > 0) 73 | { 74 | QByteArray datagram; 75 | datagram.resize(tcpSocket->bytesAvailable()); 76 | tcpSocket->read(datagram.data(),datagram.size()); 77 | QString msg = datagram.data(); 78 | contentListWidget->addItem(msg.left(datagram.size())); 79 | contentListWidget->scrollToBottom(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /daySix/ChatRoom/tcpclient.h: -------------------------------------------------------------------------------- 1 | #ifndef TCPCLIENT_H 2 | #define TCPCLIENT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class TcpClient : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | TcpClient(QWidget *parent = 0,Qt::WindowFlags f=0); 19 | ~TcpClient(); 20 | QString username; 21 | 22 | private: 23 | QListWidget *contentListWidget; 24 | QLineEdit *sendLineEdit; 25 | QPushButton *sendBtn; 26 | QPushButton *clearBtn; 27 | QGridLayout *mainLayout; 28 | int port; 29 | QString IP; 30 | QHostAddress *serverIP; 31 | QTcpSocket *tcpSocket; 32 | 33 | public slots: 34 | void slotConnected(); 35 | void dataReceived(); 36 | void slotSend(); 37 | void slotClear(); 38 | }; 39 | 40 | #endif // TCPCLIENT_H 41 | -------------------------------------------------------------------------------- /daySix/ChatRoom/widget.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include "ui_widget.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | Widget::Widget(QWidget *parent, QString usrname) : 12 | QWidget(parent), 13 | ui(new Ui::Widget) 14 | { 15 | ui->setupUi(this); 16 | uName = usrname; 17 | port = 12345; 18 | udpSocket = new QUdpSocket(this); 19 | udpSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); 20 | connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams())); 21 | connect(ui->sendBtn, SIGNAL(clicked()), this, SLOT(on_sendBtn_clicked())); 22 | sndMsg(UsrEnter); 23 | } 24 | 25 | Widget::~Widget() 26 | { 27 | delete ui; 28 | } 29 | 30 | 31 | void Widget::sndMsg(MsgType type, QString srvaddr) 32 | { 33 | QByteArray data; 34 | QDataStream out(&data, QIODevice::WriteOnly); 35 | QString address = getIP(); 36 | out << type << getUsr(); 37 | switch(type) 38 | { 39 | case Msg: 40 | if(ui->msgTxtEdit->toPlainText() == "") 41 | { 42 | return; 43 | } 44 | out << address << getMsg(); 45 | ui->msgBrowser->verticalScrollBar()->setValue(ui->msgBrowser->verticalScrollBar()->maximum()); 46 | break; 47 | case UsrEnter: 48 | out << address; 49 | break; 50 | case UsrLeft: 51 | break; 52 | case FileName: { 53 | break; 54 | } 55 | case Refuse: 56 | break; 57 | } 58 | 59 | udpSocket->writeDatagram(data, data.length(), QHostAddress::Broadcast, port); 60 | } 61 | 62 | 63 | void Widget::processPendingDatagrams() 64 | { 65 | while(udpSocket->hasPendingDatagrams()) 66 | { 67 | QByteArray datagram; 68 | //获取当前可供读取的UDP报文大小,并据此大小分配接收缓冲区 69 | datagram.resize(udpSocket->pendingDatagramSize()); 70 | 71 | udpSocket->readDatagram(datagram.data(), datagram.size()); 72 | QDataStream in(&datagram, QIODevice::ReadOnly); 73 | int msgType; 74 | in >> msgType; 75 | QString usrName, ipAddr, msg; 76 | QString time = QDateTime::currentDateTime().toString("yyy-MM-dd hh:mm:ss"); 77 | 78 | switch(msgType) 79 | { 80 | case Msg: 81 | in >> usrName >> ipAddr >> msg; 82 | ui->msgBrowser->setTextColor(Qt::blue); 83 | ui->msgBrowser->setCurrentFont(QFont("Times New Roman", 12)); 84 | ui->msgBrowser->append(" [ " + usrName + " ] " + time); 85 | ui->msgBrowser->append(msg); 86 | break; 87 | case UsrEnter: 88 | in >> usrName >> ipAddr; 89 | usrEnter(usrName, ipAddr); 90 | break; 91 | case UsrLeft: 92 | in >> usrName; 93 | usrLeft(usrName, time); 94 | break; 95 | case FileName: { 96 | break; 97 | } 98 | case Refuse: 99 | break; 100 | } 101 | } 102 | } 103 | 104 | void Widget::usrEnter(QString usrname, QString ipaddr) 105 | { 106 | //判断是否已经在用户列表中 107 | bool isEmpty = ui->usrTblWidget->findItems(usrname, Qt::MatchExactly).isEmpty(); 108 | if(isEmpty) 109 | { 110 | QTableWidgetItem *usr = new QTableWidgetItem(usrname); 111 | QTableWidgetItem *ip = new QTableWidgetItem(ipaddr); 112 | ui->usrTblWidget->insertRow(0); 113 | ui->usrTblWidget->setItem(0, 0, usr); 114 | ui->usrTblWidget->setItem(0, 1, ip); 115 | ui->msgBrowser->setTextColor(Qt::gray); 116 | ui->msgBrowser->setCurrentFont(QFont("Times New Roman", 10)); 117 | ui->msgBrowser->append(tr("%1 online").arg(usrname)); 118 | ui->usrNumLbl->setText(tr("%1 online people").arg(ui->usrTblWidget->rowCount())); 119 | sndMsg(UsrEnter); 120 | } 121 | } 122 | 123 | void Widget::usrLeft(QString usrname, QString time) 124 | { 125 | int rowNum = ui->usrTblWidget->findItems(usrname, Qt::MatchExactly).first()->row(); 126 | ui->usrTblWidget->removeRow(rowNum); 127 | ui->msgBrowser->setTextColor(Qt::gray); 128 | ui->msgBrowser->setCurrentFont(QFont("Times New Roman", 10)); 129 | ui->msgBrowser->append(tr("%1 left at %2").arg(usrname).arg(time)); 130 | ui->usrNumLbl->setText(tr("%1 online people").arg(ui->usrTblWidget->rowCount())); 131 | } 132 | 133 | 134 | QString Widget::getIP() 135 | { 136 | QList list = QNetworkInterface::allAddresses(); 137 | foreach (QHostAddress addr, list) { 138 | if(addr.protocol() == QAbstractSocket::IPv4Protocol) 139 | return addr.toString(); 140 | } 141 | return 0; 142 | } 143 | 144 | QString Widget::getUsr() 145 | { 146 | return uName; 147 | } 148 | 149 | QString Widget::getMsg() 150 | { 151 | QString msg = ui->msgTxtEdit->toHtml(); 152 | ui->msgTxtEdit->clear(); 153 | ui->msgTxtEdit->setFocus(); 154 | return msg; 155 | } 156 | 157 | void Widget::on_sendBtn_clicked() 158 | { 159 | sndMsg(Msg); 160 | } 161 | 162 | void Widget::on_exitBtn_clicked() 163 | { 164 | close(); 165 | } 166 | -------------------------------------------------------------------------------- /daySix/ChatRoom/widget.h: -------------------------------------------------------------------------------- 1 | #ifndef WIDGET_H 2 | #define WIDGET_H 3 | 4 | #include 5 | #include "command.h" 6 | 7 | class QUdpSocket; 8 | 9 | namespace Ui { 10 | class Widget; 11 | } 12 | 13 | class Widget : public QWidget 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit Widget(QWidget *parent, QString usrname); 19 | ~Widget(); 20 | 21 | protected: 22 | void usrEnter(QString, QString); 23 | void usrLeft(QString, QString); 24 | void sndMsg(MsgType type, QString srvaddr = ""); 25 | QString getIP(); 26 | QString getMsg(); 27 | QString getUsr(); 28 | 29 | private: 30 | Ui::Widget *ui; 31 | 32 | QUdpSocket *udpSocket; 33 | qint16 port; 34 | QString uName; 35 | 36 | private slots: 37 | void processPendingDatagrams(); 38 | void on_sendBtn_clicked(); 39 | void on_exitBtn_clicked(); 40 | }; 41 | 42 | #endif // WIDGET_H 43 | -------------------------------------------------------------------------------- /daySix/ChatRoom/widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Widget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 780 10 | 450 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 5 20 | 11 21 | 541 22 | 231 23 | 24 | 25 | 26 | 27 | 28 | 29 | 3 30 | 280 31 | 541 32 | 131 33 | 34 | 35 | 36 | 37 | 38 | 39 | 555 40 | 11 41 | 221 42 | 401 43 | 44 | 45 | 46 | QAbstractItemView::SingleSelection 47 | 48 | 49 | QAbstractItemView::SelectRows 50 | 51 | 52 | 53 | 新建列 54 | 55 | 56 | 57 | 58 | ipAddress 59 | 60 | 61 | 62 | 63 | 64 | 65 | 0 66 | 250 67 | 213 68 | 22 69 | 70 | 71 | 72 | 73 | 74 | 75 | 230 76 | 250 77 | 69 78 | 22 79 | 80 | 81 | 82 | 4 83 | 84 | 85 | 86 | 8 87 | 88 | 89 | 90 | 91 | 9 92 | 93 | 94 | 95 | 96 | 10 97 | 98 | 99 | 100 | 101 | 11 102 | 103 | 104 | 105 | 106 | 12 107 | 108 | 109 | 110 | 111 | 13 112 | 113 | 114 | 115 | 116 | 14 117 | 118 | 119 | 120 | 121 | 15 122 | 123 | 124 | 125 | 126 | 16 127 | 128 | 129 | 130 | 131 | 17 132 | 133 | 134 | 135 | 136 | 18 137 | 138 | 139 | 140 | 141 | 19 142 | 143 | 144 | 145 | 146 | 20 147 | 148 | 149 | 150 | 151 | 21 152 | 153 | 154 | 155 | 156 | 22 157 | 158 | 159 | 160 | 161 | 162 | 163 | 460 164 | 420 165 | 75 166 | 23 167 | 168 | 169 | 170 | Send 171 | 172 | 173 | 174 | 175 | 176 | 560 177 | 420 178 | 75 179 | 23 180 | 181 | 182 | 183 | Exit 184 | 185 | 186 | 187 | 188 | 189 | 660 190 | 420 191 | 91 192 | 20 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /daySix/ChatRoomV0.1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/daySix/ChatRoomV0.1.PNG -------------------------------------------------------------------------------- /daySix/README.md: -------------------------------------------------------------------------------- 1 | ## daySix 2 | 1. 今天再把重心转向客户端,我们都知道一般的聊天软件肯定都要账号和密码,我们今天就实现它 3 | 4 | 5 | ### ChatRoom与Chat+mysql中的服务器一起运行: 6 | #### (Chat+MySQL是由之前的服务器加上了MySQL数据库的操作,还不完善) 7 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/daySix/ChatRoomV0.1.PNG) 8 | -------------------------------------------------------------------------------- /dayThree/README.md: -------------------------------------------------------------------------------- 1 | ## dayThree 2 | 学习qt,然后写出一个图形界面的客户端,暂时先不考虑没不美观、只考虑功能实现 3 | 4 | ### Linux环境下运行的客户端: 5 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayThree/TcpClient.png) 6 | 7 | ### Windows7环境下运行的客户端: 8 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayThree/TcpClient2.png) 9 | 10 | ### 与dayOne实现的服务器一起运行: 11 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayThree/chatRoomV0.1.png) 12 | -------------------------------------------------------------------------------- /dayThree/TcpClient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/dayThree/TcpClient.png -------------------------------------------------------------------------------- /dayThree/TcpClient/TcpClient.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2017-02-18T08:51:00 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QT += network 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = TcpClient 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which as been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += main.cpp\ 27 | tcpclient.cpp 28 | 29 | HEADERS += tcpclient.h 30 | -------------------------------------------------------------------------------- /dayThree/TcpClient/TcpClient.pro.user.49007d5: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {49007d51-0203-4643-82cc-95ce042304fb} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.8.0 MinGW 32bit 63 | Desktop Qt 5.8.0 MinGW 32bit 64 | qt.58.win32_mingw53_kit 65 | 0 66 | 0 67 | 0 68 | 69 | D:/Qt/CH10/CH1005/build-TcpClient-Desktop_Qt_5_8_0_MinGW_32bit-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | false 89 | 90 | 91 | 92 | 2 93 | 构建 94 | 95 | ProjectExplorer.BuildSteps.Build 96 | 97 | 98 | 99 | true 100 | Make 101 | 102 | Qt4ProjectManager.MakeStep 103 | 104 | true 105 | clean 106 | 107 | 108 | 1 109 | 清理 110 | 111 | ProjectExplorer.BuildSteps.Clean 112 | 113 | 2 114 | false 115 | 116 | Debug 117 | 118 | Qt4ProjectManager.Qt4BuildConfiguration 119 | 2 120 | true 121 | 122 | 123 | D:/Qt/CH10/CH1005/build-TcpClient-Desktop_Qt_5_8_0_MinGW_32bit-Release 124 | 125 | 126 | true 127 | qmake 128 | 129 | QtProjectManager.QMakeBuildStep 130 | false 131 | 132 | false 133 | false 134 | false 135 | 136 | 137 | true 138 | Make 139 | 140 | Qt4ProjectManager.MakeStep 141 | 142 | false 143 | 144 | 145 | 146 | 2 147 | 构建 148 | 149 | ProjectExplorer.BuildSteps.Build 150 | 151 | 152 | 153 | true 154 | Make 155 | 156 | Qt4ProjectManager.MakeStep 157 | 158 | true 159 | clean 160 | 161 | 162 | 1 163 | 清理 164 | 165 | ProjectExplorer.BuildSteps.Clean 166 | 167 | 2 168 | false 169 | 170 | Release 171 | 172 | Qt4ProjectManager.Qt4BuildConfiguration 173 | 0 174 | true 175 | 176 | 177 | D:/Qt/CH10/CH1005/build-TcpClient-Desktop_Qt_5_8_0_MinGW_32bit-Profile 178 | 179 | 180 | true 181 | qmake 182 | 183 | QtProjectManager.QMakeBuildStep 184 | true 185 | 186 | false 187 | true 188 | false 189 | 190 | 191 | true 192 | Make 193 | 194 | Qt4ProjectManager.MakeStep 195 | 196 | false 197 | 198 | 199 | 200 | 2 201 | 构建 202 | 203 | ProjectExplorer.BuildSteps.Build 204 | 205 | 206 | 207 | true 208 | Make 209 | 210 | Qt4ProjectManager.MakeStep 211 | 212 | true 213 | clean 214 | 215 | 216 | 1 217 | 清理 218 | 219 | ProjectExplorer.BuildSteps.Clean 220 | 221 | 2 222 | false 223 | 224 | Profile 225 | 226 | Qt4ProjectManager.Qt4BuildConfiguration 227 | 0 228 | true 229 | 230 | 3 231 | 232 | 233 | 0 234 | 部署 235 | 236 | ProjectExplorer.BuildSteps.Deploy 237 | 238 | 1 239 | 在本地部署 240 | 241 | ProjectExplorer.DefaultDeployConfiguration 242 | 243 | 1 244 | 245 | 246 | false 247 | false 248 | 1000 249 | 250 | true 251 | 252 | false 253 | false 254 | false 255 | false 256 | true 257 | 0.01 258 | 10 259 | true 260 | 1 261 | 25 262 | 263 | 1 264 | true 265 | false 266 | true 267 | valgrind 268 | 269 | 0 270 | 1 271 | 2 272 | 3 273 | 4 274 | 5 275 | 6 276 | 7 277 | 8 278 | 9 279 | 10 280 | 11 281 | 12 282 | 13 283 | 14 284 | 285 | 2 286 | 287 | TcpClient 288 | 289 | Qt4ProjectManager.Qt4RunConfiguration:D:/Qt/CH10/CH1005/TcpClient/TcpClient.pro 290 | true 291 | 292 | TcpClient.pro 293 | false 294 | 295 | 296 | 3768 297 | false 298 | true 299 | false 300 | false 301 | true 302 | 303 | 1 304 | 305 | 306 | 307 | ProjectExplorer.Project.TargetCount 308 | 1 309 | 310 | 311 | ProjectExplorer.Project.Updater.FileVersion 312 | 18 313 | 314 | 315 | Version 316 | 18 317 | 318 | 319 | -------------------------------------------------------------------------------- /dayThree/TcpClient/main.cpp: -------------------------------------------------------------------------------- 1 | #include "tcpclient.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QApplication a(argc, argv); 9 | QPixmap pixmap("Linux.jpg"); //启动程序前显示的图片 10 | QSplashScreen splash(pixmap); 11 | splash.show(); 12 | a.processEvents(); 13 | 14 | TcpClient w; 15 | w.show(); 16 | splash.finish(&w); 17 | 18 | return a.exec(); 19 | } 20 | -------------------------------------------------------------------------------- /dayThree/TcpClient/tcpclient.cpp: -------------------------------------------------------------------------------- 1 | #include "tcpclient.h" 2 | #include 3 | #include 4 | 5 | TcpClient::TcpClient(QWidget *parent,Qt::WindowFlags f) 6 | : QDialog(parent,f) 7 | { 8 | setWindowTitle(tr("TCP Client")); 9 | contentListWidget = new QListWidget; 10 | sendLineEdit = new QLineEdit; 11 | sendBtn = new QPushButton(tr("Send")); 12 | clearBtn = new QPushButton(tr("Clear")); 13 | userNameLabel = new QLabel(tr("Username:")); 14 | userNameLineEdit = new QLineEdit; 15 | serverIPLabel = new QLabel(tr("Server IP Address:")); 16 | serverIPLineEdit = new QLineEdit; 17 | portLabel = new QLabel(tr("Port:")); 18 | portLineEdit = new QLineEdit; 19 | enterBtn= new QPushButton(tr("Enter Chat Room")); 20 | mainLayout = new QGridLayout(this); 21 | mainLayout->addWidget(contentListWidget,0,0,1,3); 22 | mainLayout->addWidget(sendLineEdit,1,0); 23 | mainLayout->addWidget(sendBtn,1,1); 24 | mainLayout->addWidget(clearBtn,1,2); 25 | mainLayout->addWidget(userNameLabel,2,0); 26 | mainLayout->addWidget(userNameLineEdit,2,1,1,2); 27 | mainLayout->addWidget(serverIPLabel,3,0); 28 | mainLayout->addWidget(serverIPLineEdit,3,1,1,2); 29 | mainLayout->addWidget(portLabel,4,0); 30 | mainLayout->addWidget(portLineEdit,4,1,1,2); 31 | mainLayout->addWidget(enterBtn,5,0,1,3); 32 | status = false; 33 | port = 12345; 34 | portLineEdit->setText(QString::number(port)); 35 | IP = "127.0.0.1"; 36 | serverIPLineEdit->setText(IP); 37 | serverIP = new QHostAddress(); 38 | connect(enterBtn,SIGNAL(clicked()),this,SLOT(slotEnter())); 39 | connect(sendBtn,SIGNAL(clicked()),this,SLOT(slotSend())); 40 | connect(clearBtn,SIGNAL(clicked()),this,SLOT(slotClear())); 41 | sendBtn->setEnabled(false); 42 | } 43 | 44 | void TcpClient::slotEnter() 45 | { 46 | if(!status) 47 | { 48 | /* 完成输入合法性检验 */ 49 | QString ip = serverIPLineEdit->text(); 50 | if(!serverIP->setAddress(ip)) 51 | { 52 | QMessageBox::information(this,tr("error"),tr("server ip address error!")); 53 | return; 54 | } 55 | if(userNameLineEdit->text()=="") 56 | { 57 | QMessageBox::information(this,tr("error"),tr("User name error!")); 58 | return; 59 | } 60 | userName = userNameLineEdit->text(); 61 | /* 创建了一个QTcpSocket类对象,并将信号/槽连接起来 */ 62 | tcpSocket = new QTcpSocket(this); 63 | connect(tcpSocket,SIGNAL(connected()),this,SLOT (slotConnected())); 64 | connect(tcpSocket,SIGNAL(disconnected()),this,SLOT (slotDisconnected ())); 65 | connect(tcpSocket,SIGNAL(readyRead()),this,SLOT (dataReceived())); 66 | tcpSocket->connectToHost(*serverIP,port); 67 | status=true; 68 | } 69 | else 70 | { 71 | int length=0; 72 | QString msg = userName + tr(":Leave Chat Room"); 73 | if((length=tcpSocket->write(msg.toLatin1(),msg. length()))!=msg. length()) 74 | { 75 | return; 76 | } 77 | tcpSocket->disconnectFromHost(); 78 | status=false; //将status状态复位 79 | } 80 | } 81 | 82 | void TcpClient::slotConnected() 83 | { 84 | sendBtn->setEnabled(true); 85 | enterBtn->setText(tr("leave")); 86 | int length=0; 87 | QString msg=userName+tr(":Enter Chat Room"); 88 | if((length=tcpSocket->write(msg.toLatin1(),msg. length()))!=msg.length()) 89 | { 90 | return; 91 | } 92 | } 93 | 94 | void TcpClient::slotSend() 95 | { 96 | if(sendLineEdit->text()=="") 97 | { 98 | return ; 99 | } 100 | //QString msg=userName+":"+sendLineEdit->text(); 101 | QString msg = sendLineEdit->text(); 102 | tcpSocket->write(msg.toLatin1(), msg.length()); 103 | sendLineEdit->clear(); 104 | } 105 | 106 | void TcpClient::slotDisconnected() 107 | { 108 | sendBtn->setEnabled(false); 109 | enterBtn->setText(tr("Enter Chat Room")); 110 | } 111 | 112 | void TcpClient::slotClear() 113 | { 114 | contentListWidget->clear(); 115 | } 116 | 117 | void TcpClient::dataReceived() 118 | { 119 | while(tcpSocket->bytesAvailable()>0) 120 | { 121 | QByteArray datagram; 122 | datagram.resize(tcpSocket->bytesAvailable()); 123 | tcpSocket->read(datagram.data(),datagram.size()); 124 | QString msg=datagram.data(); 125 | contentListWidget->addItem(msg.left(datagram.size())); 126 | contentListWidget->scrollToBottom(); 127 | } 128 | } 129 | 130 | TcpClient::~TcpClient() 131 | { 132 | } 133 | -------------------------------------------------------------------------------- /dayThree/TcpClient/tcpclient.h: -------------------------------------------------------------------------------- 1 | #ifndef TCPCLIENT_H 2 | #define TCPCLIENT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class TcpClient : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | TcpClient(QWidget *parent = 0,Qt::WindowFlags f=0); 19 | ~TcpClient(); 20 | 21 | private: 22 | QListWidget *contentListWidget; 23 | QLineEdit *sendLineEdit; 24 | QPushButton *sendBtn; 25 | QPushButton *clearBtn; 26 | QLabel *userNameLabel; 27 | QLineEdit *userNameLineEdit; 28 | QLabel *serverIPLabel; 29 | QLineEdit *serverIPLineEdit; 30 | QLabel *portLabel; 31 | QLineEdit *portLineEdit; 32 | QPushButton *enterBtn; 33 | QGridLayout *mainLayout; 34 | bool status; 35 | int port; 36 | QString IP; 37 | QHostAddress *serverIP; 38 | QString userName; 39 | QTcpSocket *tcpSocket; 40 | 41 | public slots: 42 | void slotEnter(); 43 | void slotConnected(); 44 | void slotDisconnected(); 45 | void dataReceived(); 46 | void slotSend(); 47 | void slotClear(); 48 | }; 49 | 50 | #endif // TCPCLIENT_H 51 | -------------------------------------------------------------------------------- /dayThree/TcpClient2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/dayThree/TcpClient2.png -------------------------------------------------------------------------------- /dayThree/bin/TcpClient: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/dayThree/bin/TcpClient -------------------------------------------------------------------------------- /dayThree/chatRoomV0.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/dayThree/chatRoomV0.1.png -------------------------------------------------------------------------------- /dayTwo/README.md: -------------------------------------------------------------------------------- 1 | ## dayTwo 2 | 学习qt,并实现一个能和服务端连接上并且能交流的一个TCP客户端demo 3 | 4 | ### Linux环境下运行的TCP客户端: 5 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayTwo/communication.png) 6 | 7 | ### Windows7环境下运行的TCP客户端: 8 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayTwo/communication2.png) 9 | 10 | ### 与dayOne实现的服务器一起运行: 11 | ![](https://github.com/liu-jianhao/chatRoom/blob/master/dayTwo/TcpClientV0.01.png) 12 | -------------------------------------------------------------------------------- /dayTwo/TcpClientV0.01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/dayTwo/TcpClientV0.01.png -------------------------------------------------------------------------------- /dayTwo/communication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/dayTwo/communication.png -------------------------------------------------------------------------------- /dayTwo/communication/communication.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-07-12T14:11:15 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QT += network 9 | 10 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 11 | 12 | TARGET = communication 13 | TEMPLATE = app 14 | 15 | # The following define makes your compiler emit warnings if you use 16 | # any feature of Qt which as been marked as deprecated (the exact warnings 17 | # depend on your compiler). Please consult the documentation of the 18 | # deprecated API in order to know how to port your code away from it. 19 | DEFINES += QT_DEPRECATED_WARNINGS 20 | 21 | # You can also make your code fail to compile if you use deprecated APIs. 22 | # In order to do so, uncomment the following line. 23 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 24 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 25 | 26 | 27 | SOURCES += main.cpp\ 28 | dialog.cpp 29 | 30 | HEADERS += dialog.h 31 | -------------------------------------------------------------------------------- /dayTwo/communication/communication.pro.user.0360db3: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {0360db30-20c5-4c1d-9aaf-58d00c53f6cd} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.8.0 MinGW 32bit 63 | Desktop Qt 5.8.0 MinGW 32bit 64 | qt.58.win32_mingw53_kit 65 | 0 66 | 0 67 | 0 68 | 69 | D:/QT/build-communication-Desktop_Qt_5_8_0_MinGW_32bit-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | false 89 | 90 | 91 | 92 | 2 93 | 构建 94 | 95 | ProjectExplorer.BuildSteps.Build 96 | 97 | 98 | 99 | true 100 | Make 101 | 102 | Qt4ProjectManager.MakeStep 103 | 104 | true 105 | clean 106 | 107 | 108 | 1 109 | 清理 110 | 111 | ProjectExplorer.BuildSteps.Clean 112 | 113 | 2 114 | false 115 | 116 | Debug 117 | 118 | Qt4ProjectManager.Qt4BuildConfiguration 119 | 2 120 | true 121 | 122 | 123 | D:/QT/build-communication-Desktop_Qt_5_8_0_MinGW_32bit-Release 124 | 125 | 126 | true 127 | qmake 128 | 129 | QtProjectManager.QMakeBuildStep 130 | false 131 | 132 | false 133 | false 134 | false 135 | 136 | 137 | true 138 | Make 139 | 140 | Qt4ProjectManager.MakeStep 141 | 142 | false 143 | 144 | 145 | 146 | 2 147 | 构建 148 | 149 | ProjectExplorer.BuildSteps.Build 150 | 151 | 152 | 153 | true 154 | Make 155 | 156 | Qt4ProjectManager.MakeStep 157 | 158 | true 159 | clean 160 | 161 | 162 | 1 163 | 清理 164 | 165 | ProjectExplorer.BuildSteps.Clean 166 | 167 | 2 168 | false 169 | 170 | Release 171 | 172 | Qt4ProjectManager.Qt4BuildConfiguration 173 | 0 174 | true 175 | 176 | 177 | D:/QT/build-communication-Desktop_Qt_5_8_0_MinGW_32bit-Profile 178 | 179 | 180 | true 181 | qmake 182 | 183 | QtProjectManager.QMakeBuildStep 184 | true 185 | 186 | false 187 | true 188 | false 189 | 190 | 191 | true 192 | Make 193 | 194 | Qt4ProjectManager.MakeStep 195 | 196 | false 197 | 198 | 199 | 200 | 2 201 | 构建 202 | 203 | ProjectExplorer.BuildSteps.Build 204 | 205 | 206 | 207 | true 208 | Make 209 | 210 | Qt4ProjectManager.MakeStep 211 | 212 | true 213 | clean 214 | 215 | 216 | 1 217 | 清理 218 | 219 | ProjectExplorer.BuildSteps.Clean 220 | 221 | 2 222 | false 223 | 224 | Profile 225 | 226 | Qt4ProjectManager.Qt4BuildConfiguration 227 | 0 228 | true 229 | 230 | 3 231 | 232 | 233 | 0 234 | 部署 235 | 236 | ProjectExplorer.BuildSteps.Deploy 237 | 238 | 1 239 | 在本地部署 240 | 241 | ProjectExplorer.DefaultDeployConfiguration 242 | 243 | 1 244 | 245 | 246 | false 247 | false 248 | 1000 249 | 250 | true 251 | 252 | false 253 | false 254 | false 255 | false 256 | true 257 | 0.01 258 | 10 259 | true 260 | 1 261 | 25 262 | 263 | 1 264 | true 265 | false 266 | true 267 | valgrind 268 | 269 | 0 270 | 1 271 | 2 272 | 3 273 | 4 274 | 5 275 | 6 276 | 7 277 | 8 278 | 9 279 | 10 280 | 11 281 | 12 282 | 13 283 | 14 284 | 285 | 2 286 | 287 | communication 288 | 289 | Qt4ProjectManager.Qt4RunConfiguration:D:/QT/communication/communication.pro 290 | true 291 | 292 | communication.pro 293 | false 294 | 295 | D:/QT/build-communication-Desktop_Qt_5_8_0_MinGW_32bit-Debug 296 | 3768 297 | false 298 | true 299 | false 300 | false 301 | true 302 | 303 | 1 304 | 305 | 306 | 307 | ProjectExplorer.Project.TargetCount 308 | 1 309 | 310 | 311 | ProjectExplorer.Project.Updater.FileVersion 312 | 18 313 | 314 | 315 | Version 316 | 18 317 | 318 | 319 | -------------------------------------------------------------------------------- /dayTwo/communication/dialog.cpp: -------------------------------------------------------------------------------- 1 | #include "dialog.h" 2 | #include 3 | #include 4 | 5 | Dialog::Dialog(QWidget *parent) 6 | : QDialog(parent) 7 | { 8 | setWindowTitle(tr("communication")); 9 | contentListWidget = new QListWidget; 10 | signINBtn = new QPushButton(tr("sign in")); 11 | signUpBtn = new QPushButton(tr("sign up")); 12 | disconnectBtn = new QPushButton(tr("disconect")); 13 | mainLayout = new QGridLayout(this); 14 | mainLayout->addWidget(contentListWidget, 0, 0, 1, 3); 15 | mainLayout->addWidget(signINBtn, 1, 0); 16 | mainLayout->addWidget(signUpBtn, 1, 1); 17 | mainLayout->addWidget(disconnectBtn, 1, 2); 18 | 19 | connect(signINBtn, SIGNAL(clicked()), this, SLOT(slotSignin())); 20 | connect(signUpBtn, SIGNAL(clicked()), this, SLOT(slotSignup())); 21 | 22 | //连接服务器 23 | tcpSocket = new QTcpSocket(this); 24 | connect(disconnectBtn, SIGNAL(clicked()), this, SLOT(slotDisconnect())); 25 | connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReceived())); 26 | port = 12345; 27 | serverIP = new QHostAddress(); 28 | QString ip = "127.0.0.1"; 29 | serverIP->setAddress(ip); 30 | tcpSocket->connectToHost(*serverIP, port); 31 | } 32 | 33 | Dialog::~Dialog() 34 | { 35 | } 36 | 37 | void Dialog::slotSignin() 38 | { 39 | QString msg = tr("sign in"); 40 | int length = tcpSocket->write(msg.toLatin1(), msg.length()); 41 | if(length != msg.length()) 42 | { 43 | return; 44 | } 45 | } 46 | 47 | 48 | void Dialog::slotDisconnect() 49 | { 50 | tcpSocket->disconnectFromHost(); 51 | } 52 | 53 | void Dialog::slotSignup() 54 | { 55 | QString msg = tr("sign up"); 56 | int length = tcpSocket->write(msg.toLatin1(), msg.length()); 57 | if(length != msg.length()) 58 | { 59 | return; 60 | } 61 | } 62 | 63 | void Dialog::dataReceived() 64 | { 65 | QByteArray datagram; 66 | datagram.resize(tcpSocket->bytesAvailable()); 67 | tcpSocket->read(datagram.data(), datagram.size()); 68 | QString msg = datagram.data(); 69 | contentListWidget->addItem(msg.left(datagram.size())); 70 | contentListWidget->scrollToBottom(); //自动回滚信息 71 | } 72 | -------------------------------------------------------------------------------- /dayTwo/communication/dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef DIALOG_H 2 | #define DIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class Dialog : public QDialog 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | Dialog(QWidget *parent = 0); 17 | ~Dialog(); 18 | 19 | private: 20 | QGridLayout *mainLayout; 21 | QListWidget *contentListWidget; 22 | QPushButton *signINBtn; 23 | QPushButton *signUpBtn; 24 | QPushButton *disconnectBtn; 25 | 26 | int port; 27 | QHostAddress *serverIP; 28 | QTcpSocket *tcpSocket; 29 | public slots: 30 | void slotSignin(); 31 | void slotSignup(); 32 | void slotDisconnect(); 33 | void dataReceived(); 34 | }; 35 | 36 | #endif // DIALOG_H 37 | -------------------------------------------------------------------------------- /dayTwo/communication/main.cpp: -------------------------------------------------------------------------------- 1 | #include "dialog.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | Dialog w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /dayTwo/communication2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/chatRoom/71a09931f3c86516d8b9c46757de5e5ae6857ddd/dayTwo/communication2.png --------------------------------------------------------------------------------