当前位置:   article > 正文

C++:C/S架构,通过TCP实现双向自由通信_c++ tcp设置非阻塞

c++ tcp设置非阻塞

首先写一个TCP.hpp的准备文件

  1. #ifndef TCP_HPP
  2. #define TCP_HPP
  3. #include <iostream>
  4. #include <cstring>
  5. extern "C"
  6. {
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <unistd.h>
  11. #include <pthread.h>
  12. #include <fcntl.h>
  13. }
  14. //设置套接字为非阻塞模式
  15. int setNonBlocking(int &sockfd)
  16. {
  17. //获取套接字当前状态 获取状态
  18. int flags = fcntl(sockfd, F_GETFL, 0);
  19. if (flags == -1)
  20. {
  21. return -1;
  22. }
  23. //将表示非阻塞模式的那一个标志位设置为1
  24. flags |= O_NONBLOCK;
  25. // 设置状态
  26. if (fcntl(sockfd, F_SETFL, flags) == -1)
  27. {
  28. return -1;
  29. }
  30. return 0;
  31. }
  32. class socketSend
  33. {
  34. public:
  35. bool running;
  36. socketSend(int fd) : client_fd(fd), running(true) {}
  37. void sendData() // 发送数据
  38. {
  39. char buf[1024]{};
  40. while (running)
  41. {
  42. memset(buf, 0, sizeof(buf));
  43. if (fgets(buf, sizeof(buf), stdin) == nullptr)
  44. continue;
  45. buf[strcspn(buf, "\n")] = '\0'; // 结束符替换换行符
  46. if (send(client_fd, buf, strlen(buf), 0) == -1)
  47. {
  48. perror("send()");
  49. continue;
  50. }
  51. if (strcmp(buf, "exit") == 0)
  52. {
  53. running = false;
  54. break;
  55. }
  56. }
  57. }
  58. private:
  59. int client_fd;
  60. };
  61. void *sendDataHelper(void *arg)//发送数据
  62. {
  63. socketSend *c1 = (socketSend *)arg;
  64. c1->sendData();
  65. return nullptr;
  66. }
  67. #endif

服务端代码

  1. #include "TCP.hpp"
  2. using namespace std;
  3. int main(int argc, const char *argv[])
  4. {
  5. if (argc != 2)
  6. {
  7. cout << "需要传入端口号" << endl;
  8. return -1;
  9. }
  10. // 创建套接字
  11. int server_fd = socket(PF_INET, SOCK_STREAM, 0);
  12. if (server_fd == -1)
  13. {
  14. perror("socket()");
  15. return -1;
  16. }
  17. // 设置服务端ip和端口
  18. sockaddr_in serverAddr;
  19. memset(&serverAddr, 0, sizeof(serverAddr));
  20. serverAddr.sin_family = AF_INET;
  21. serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 主机字节序=>网络字节序
  22. serverAddr.sin_port = htons(atoi(argv[1])); // 字符串=>整数=>16位网络字节序二进制值
  23. // 绑定套接字
  24. if (bind(server_fd, (sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)
  25. {
  26. perror("bind()");
  27. close(server_fd);
  28. return -1;
  29. }
  30. // 设置监听
  31. if (listen(server_fd, 5) == -1)
  32. {
  33. perror("listen()");
  34. close(server_fd);
  35. return -1;
  36. }
  37. cout << "等待连接......" << endl;
  38. // 接收连接
  39. sockaddr_in clientAddr;
  40. memset(&clientAddr, 0, sizeof(sockaddr_in));
  41. socklen_t len = sizeof(clientAddr);
  42. int client_fd = accept(server_fd, (sockaddr *)&clientAddr, &len);
  43. if (client_fd == -1)
  44. {
  45. perror("accept()");
  46. close(client_fd);
  47. close(server_fd);
  48. return -1;
  49. }
  50. // 32位二进制网络字节序=>点分十进制字符串 0x7F000001=>“127.0.0.1”
  51. cout << "ip: " << inet_ntoa(clientAddr.sin_addr) << " 端口: "
  52. // 16位二进制网络字节序=>主机字节序 0x1234=>4660
  53. << ntohs(clientAddr.sin_port) << " 已连接到服务器!" << endl;
  54. setNonBlocking(client_fd); // 设置套接字为非阻塞
  55. socketSend c1(client_fd);
  56. pthread_t t1;
  57. pthread_create(&t1, nullptr, sendDataHelper, &c1);
  58. char msg[1024]{};
  59. while (c1.running) // 读
  60. {
  61. memset(msg, 0, sizeof(msg));
  62. if (recv(client_fd, msg, sizeof(msg), 0) == -1)
  63. {
  64. continue;
  65. }
  66. cout << "来自客户端:" << msg << endl;
  67. if (strcmp(msg, "exit") == 0)
  68. break;
  69. }
  70. pthread_cancel(t1);
  71. pthread_join(t1, nullptr);
  72. // 关闭套接字
  73. close(client_fd);
  74. close(server_fd);
  75. }

客户端代码

  1. #include "TCP.hpp"
  2. using namespace std;
  3. int main(int argc, char *argv[])
  4. {
  5. if (argc != 3)
  6. {
  7. cerr << "请传入服务器的ip和port!" << endl;
  8. return -1;
  9. }
  10. // 创建套接字
  11. int client_fd = socket(PF_INET, SOCK_STREAM, 0);
  12. if (client_fd < 0)
  13. {
  14. perror("sock()");
  15. return -1;
  16. }
  17. // 设置服务端信息
  18. sockaddr_in serverAddr;
  19. memset(&serverAddr, 0, sizeof(serverAddr));
  20. serverAddr.sin_family = AF_INET;
  21. serverAddr.sin_addr.s_addr = inet_addr(argv[1]); // 字符串=>32位网络字节序二进制值
  22. serverAddr.sin_port = htons(atoi(argv[2])); // 字符串=>整数=>16位网络字节序二进制值
  23. // 发起连接
  24. if (connect(client_fd, (sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)
  25. {
  26. perror("connect()");
  27. close(client_fd);
  28. return -1;
  29. }
  30. setNonBlocking(client_fd);// 设置套接字为非阻塞
  31. socketSend s1(client_fd);
  32. pthread_t t1;
  33. pthread_create(&t1, nullptr, sendDataHelper, &s1);
  34. char msg[1024]{};
  35. while (s1.running)//读
  36. {
  37. memset(msg, 0, sizeof(msg));
  38. if (recv(client_fd, msg, sizeof(msg), 0) == -1)
  39. {
  40. continue;
  41. }
  42. cout << "来自服务端:" << msg << endl;
  43. if (strcmp(msg, "exit") == 0)
  44. break;
  45. }
  46. pthread_cancel(t1);
  47. pthread_join(t1, nullptr);
  48. // 关闭套接字
  49. close(client_fd);
  50. }

运行结果

任意一方输入exit,结束连接

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/678767
推荐阅读
相关标签
  

闽ICP备14008679号