当前位置:   article > 正文

网络编程套接字(三)之TCP服务器简单实现_tcp 服务器 简单

tcp 服务器 简单

目录

一、服务端TcpServer

1、tcp_server.hpp

2、tcp_server.cc

二、客户端TcpClient

tcp_client.cc

三、服务器和客户端进行通信

四、完整代码


一、服务端TcpServer

首先我们需要对服务端进行封装。我们需要的成员变量有IP地址,端口号port,以及监听套接字listensock。Tcp服务器实现的一般步骤就是:创建套接字,进行绑定,监听等待连接,获取连接,开始通信服务。下面我们一一讲解。

1、tcp_server.hpp

第一步,创建套接字使用的函数和UDP完全一样,只不过我们需要把socket的第二个参数由基于数据报的SOCK_DGRAM 更改为基于字节流式的SOCK_STREAM,SOCK_STREAM提供的就是一个有序的、可靠的、全双工的、基于连接的流式服务。其他参数和后续步骤完全一样。

第二步,进行绑定时使用的bind函数及其参数设置与UDP完全一样。

第三步,TCP和UDP不一样的地方就是这里了。前面我们知道UDP不是面向连接的,而TCP是面向连接的,所以服务器和客户端之间需要建立连接。而服务器首先需要做的就是进行监听,等待客户端的连接。需要使用listen函数。

  1. NAME
  2. listen - listen for connections on a socket
  3. SYNOPSIS
  4. #include <sys/types.h> /* See NOTES */
  5. #include <sys/socket.h>
  6. int listen(int sockfd, int backlog);

参数说明:

sockfd:需要设置为监听状态的套接字对应的文件描述符。

backlog:全连接队列的最大长度。如果有多个客户端同时发来连接请求,此时未被服务器处理的连接就会放入连接队列,该参数代表的就是这个全连接队列的最大长度,一般不要设置太大,设置为5或10即可。

返回值:监听成功返回0,监听失败返回-1,同时错误码会被设置。

以上三步就是服务器的初始化。

第四步,TCP服务器初始化后就可以开始运行了,但TCP服务器在与客户端进行网络通信之前,服务器需要先获取到客户端的连接请求。我们需要使用accept函数。

  1. NAME
  2. accept, accept4 - accept a connection on a socket
  3. SYNOPSIS
  4. #include <sys/types.h> /* See NOTES */
  5. #include <sys/socket.h>
  6. int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数说明:

sockfd:特定的监听套接字,表示从该监听套接字中获取连接。

addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。

addrlen:调用时传入期望读取的addr结构体的长度,返回时代表实际读取到的addr结构体的长度,这是一个输入输出型参数。

返回值:获取连接成功返回接收到的套接字的文件描述符,获取连接失败返回-1,同时错误码会被设置。

注意:为什么获取连接成功了还要返回一个新的套接字呢?

类里面的监听套接字:用于获取客户端发来的连接请求。accept函数会不断从监听套接字当中获取新连接。
accept函数返回的套接字:用于为本次accept获取到的连接提供服务。

所以说,监听套接字的任务只是不断获取新连接,而真正为这些连接提供服务的套接字是accept函数返回的套接字,而不是监听套接字。

第五步,我们只要获取到客户端的连接,就可以对客户端进行服务了。

2、tcp_server.cc

与UDP相同,我们需要创建TCP服务器对象,然后对其进行初始化,然后运行。我们也是只需要绑定端口号即可。

二、客户端TcpClient

tcp_client.cc

作为TCP客户端,首先也是需要创建套接字。然后向服务器发起连接,最后就可以开始通信了。和UDP一样,客户端不需要绑定端口号。

客户端向服务器发起连接需要使用connect函数。

  1. NAME
  2. connect - initiate a connection on a socket
  3. SYNOPSIS
  4. #include <sys/types.h> /* See NOTES */
  5. #include <sys/socket.h>
  6. int connect(int sockfd, const struct sockaddr *addr,
  7. socklen_t addrlen);

参数说明:

sockfd:特定的套接字,表示通过该套接字发起连接请求。

addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。

addrlen:传入的addr结构体的长度。

返回值:连接或绑定成功返回0,连接失败返回-1,同时错误码会被设置。

三、服务器和客户端进行通信

首先,我们要知道:对于TCP服务器和客户端,我们也可以使用write函数和read函数进行消息的读取和发送。

我们先写一个服务,实现客户端给服务器发送什么消息,服务器就返回什么消息。

我们先写一个单进程版本的服务。tcp_server.hpp:

  1. #include <iostream>
  2. #include <string>
  3. #include <cstring>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <cassert>
  11. #include <signal.h>
  12. static int gmv = 20;
  13. static void service(int sock, const std::string &clientip, const uint16_t &clientport)
  14. {
  15. char buffer[1024];
  16. while (true)
  17. {
  18. ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
  19. if (s < 0)
  20. {
  21. std::cout << "接收信息失败!" << std::endl;
  22. break;
  23. }
  24. else if (s > 0)
  25. {
  26. buffer[s] = 0;
  27. std::cout << clientip << ":" << clientport << std::endl;
  28. }
  29. else
  30. {
  31. std::cout << "客户端关闭!" << std::endl;
  32. break;
  33. }
  34. write(sock, buffer, strlen(buffer));
  35. }
  36. }
  37. class TcpServer
  38. {
  39. public:
  40. TcpServer(const uint16_t port, const std::string &ip = "") : listensock_(-1), ip_(ip), port_(port)
  41. {
  42. }
  43. void initTcpServer()
  44. {
  45. // 1.创建套接字
  46. listensock_ = socket(AF_INET, SOCK_STREAM, 0);
  47. if (listensock_ < 0)
  48. {
  49. std::cout << "创建套接字失败!" << std::endl;
  50. exit(0);
  51. }
  52. // 2.进行绑定
  53. struct sockaddr_in src_server;
  54. bzero(&src_server, sizeof(src_server));
  55. src_server.sin_family = AF_INET;
  56. src_server.sin_port = htons(port_);
  57. inet_pton(AF_INET, ip_.c_str(), &src_server);
  58. socklen_t len = sizeof(src_server);
  59. if (bind(listensock_, (struct sockaddr *)&src_server, len) < 0)
  60. {
  61. std::cout << "绑定失败!" << std::endl;
  62. exit(1);
  63. }
  64. // 3.开始监听,等待连接
  65. if (listen(listensock_, gmv) < 0)
  66. {
  67. std::cout << "监听失败!" << std::endl;
  68. exit(2);
  69. }
  70. std::cout << "服务器初始化成功!" << std::endl;
  71. }
  72. void start()
  73. {
  74. //signal(SIGCHLD, SIG_IGN);
  75. while (true)
  76. {
  77. // 4.获取链接
  78. struct sockaddr_in client_sock;
  79. socklen_t len = sizeof(client_sock);
  80. int serversock = accept(listensock_, (struct sockaddr *)&client_sock, &len);
  81. if (serversock < 0)
  82. {
  83. std::cout << "获取链接失败!" << std::endl;
  84. exit(3);
  85. }
  86. // 5.开始通信服务
  87. uint16_t client_port = ntohs(client_sock.sin_port);
  88. std::string client_ip = inet_ntoa(client_sock.sin_addr);
  89. std::cout << "[" << client_port << "-" << client_ip << "]" << std::endl;
  90. //version 1:单进程版服务————服务器一次只能处理一个客户端,只有处理完一个,才能处理下一个
  91. service(serversock, client_ip, client_port);
  92. }
  93. }
  94. ~TcpServer()
  95. {
  96. close(listensock_);
  97. }
  98. private:
  99. int listensock_;
  100. std::string ip_;
  101. uint16_t port_;
  102. };

结果:

上面的结果没有什么问题,那么,如果我们同时有两个客户端访问服务器,会发生什么呢?

因为我们目前所写的是一个单执行流版的服务器,这个服务器一次只能为一个客户端提供服务。所以我们发现,当其中一个客户端在和服务器进行通信的时候,另一个客户端并不能与服务器通信,也就是说服务器在某一时刻只能向一个客户端提供服务,只有对一个客户端提供服务完成后,才能对下一个服务器提供服务。

很显然,这种提供服务的方式是不符合实际的,一个服务器应该要能够同时给多个客户端提供服务。所以我们需要改进代码。

多进程服务版本:既然单进程不符合实际,那么我们最先想到的就是使用多进程——创建子进程给新的连接提供服务,父进程去继续获取新的连接。

  1. #include <iostream>
  2. #include <string>
  3. #include <cstring>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <cassert>
  11. #include <signal.h>
  12. static int gmv = 20;
  13. static void service(int sock, const std::string &clientip, const uint16_t &clientport)
  14. {
  15. char buffer[1024];
  16. while (true)
  17. {
  18. ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
  19. if (s < 0)
  20. {
  21. std::cout << "接收信息失败!" << std::endl;
  22. break;
  23. }
  24. else if (s > 0)
  25. {
  26. buffer[s] = 0;
  27. std::cout << clientip << ":" << clientport << std::endl;
  28. }
  29. else
  30. {
  31. std::cout << "客户端关闭!" << std::endl;
  32. break;
  33. }
  34. write(sock, buffer, strlen(buffer));
  35. }
  36. }
  37. class TcpServer
  38. {
  39. public:
  40. TcpServer(const uint16_t port, const std::string &ip = "") : listensock_(-1), ip_(ip), port_(port)
  41. {
  42. }
  43. void initTcpServer()
  44. {
  45. // 1.创建套接字
  46. listensock_ = socket(AF_INET, SOCK_STREAM, 0);
  47. if (listensock_ < 0)
  48. {
  49. std::cout << "创建套接字失败!" << std::endl;
  50. exit(0);
  51. }
  52. // 2.进行绑定
  53. struct sockaddr_in src_server;
  54. bzero(&src_server, sizeof(src_server));
  55. src_server.sin_family = AF_INET;
  56. src_server.sin_port = htons(port_);
  57. inet_pton(AF_INET, ip_.c_str(), &src_server);
  58. socklen_t len = sizeof(src_server);
  59. if (bind(listensock_, (struct sockaddr *)&src_server, len) < 0)
  60. {
  61. std::cout << "绑定失败!" << std::endl;
  62. exit(1);
  63. }
  64. // 3.开始监听,等待连接
  65. if (listen(listensock_, gmv) < 0)
  66. {
  67. std::cout << "监听失败!" << std::endl;
  68. exit(2);
  69. }
  70. std::cout << "服务器初始化成功!" << std::endl;
  71. }
  72. void start()
  73. {
  74. signal(SIGCHLD, SIG_IGN);
  75. while (true)
  76. {
  77. // 4.获取链接
  78. struct sockaddr_in client_sock;
  79. socklen_t len = sizeof(client_sock);
  80. int serversock = accept(listensock_, (struct sockaddr *)&client_sock, &len);
  81. if (serversock < 0)
  82. {
  83. std::cout << "获取链接失败!" << std::endl;
  84. exit(3);
  85. }
  86. // 5.开始通信服务
  87. uint16_t client_port = ntohs(client_sock.sin_port);
  88. std::string client_ip = inet_ntoa(client_sock.sin_addr);
  89. std::cout << "[" << client_port << "-" << client_ip << "]" << std::endl;
  90. // version 2.0:多进程版本——创建子进程给新的连接提供服务,父进程去继续获取新的连接
  91. pid_t id = fork();
  92. assert(id != -1);
  93. if (id == 0)
  94. {
  95. // child 并且注意僵尸状态
  96. // child会继承父进程打开的文件及其fd,子进程不需要进行监听的套接字,关闭
  97. close(listensock_);
  98. //子进程只需要给连接客户端提供服务的套接字
  99. service(serversock, client_ip, client_port);
  100. exit(0);
  101. }
  102. close(serversock);
  103. }
  104. }
  105. ~TcpServer()
  106. {
  107. close(listensock_);
  108. }
  109. private:
  110. int listensock_;
  111. std::string ip_;
  112. uint16_t port_;
  113. };

结果:

这种方法可以解决问题。

当然,我们还有如下的多进程版本:

  1. #include <iostream>
  2. #include <string>
  3. #include <cstring>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <cassert>
  11. #include <signal.h>
  12. static int gmv = 20;
  13. static void service(int sock, const std::string &clientip, const uint16_t &clientport)
  14. {
  15. char buffer[1024];
  16. while (true)
  17. {
  18. ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
  19. if (s < 0)
  20. {
  21. std::cout << "接收信息失败!" << std::endl;
  22. break;
  23. }
  24. else if (s > 0)
  25. {
  26. buffer[s] = 0;
  27. std::cout << clientip << ":" << clientport << std::endl;
  28. }
  29. else
  30. {
  31. std::cout << "客户端关闭!" << std::endl;
  32. break;
  33. }
  34. write(sock, buffer, strlen(buffer));
  35. }
  36. }
  37. class TcpServer
  38. {
  39. public:
  40. TcpServer(const uint16_t port, const std::string &ip = "") : listensock_(-1), ip_(ip), port_(port)
  41. {
  42. }
  43. void initTcpServer()
  44. {
  45. // 1.创建套接字
  46. listensock_ = socket(AF_INET, SOCK_STREAM, 0);
  47. if (listensock_ < 0)
  48. {
  49. std::cout << "创建套接字失败!" << std::endl;
  50. exit(0);
  51. }
  52. // 2.进行绑定
  53. struct sockaddr_in src_server;
  54. bzero(&src_server, sizeof(src_server));
  55. src_server.sin_family = AF_INET;
  56. src_server.sin_port = htons(port_);
  57. inet_pton(AF_INET, ip_.c_str(), &src_server);
  58. socklen_t len = sizeof(src_server);
  59. if (bind(listensock_, (struct sockaddr *)&src_server, len) < 0)
  60. {
  61. std::cout << "绑定失败!" << std::endl;
  62. exit(1);
  63. }
  64. // 3.开始监听,等待连接
  65. if (listen(listensock_, gmv) < 0)
  66. {
  67. std::cout << "监听失败!" << std::endl;
  68. exit(2);
  69. }
  70. std::cout << "服务器初始化成功!" << std::endl;
  71. }
  72. void start()
  73. {
  74. while (true)
  75. {
  76. // 4.获取链接
  77. struct sockaddr_in client_sock;
  78. socklen_t len = sizeof(client_sock);
  79. int serversock = accept(listensock_, (struct sockaddr *)&client_sock, &len);
  80. if (serversock < 0)
  81. {
  82. std::cout << "获取链接失败!" << std::endl;
  83. exit(3);
  84. }
  85. // 5.开始通信服务
  86. uint16_t client_port = ntohs(client_sock.sin_port);
  87. std::string client_ip = inet_ntoa(client_sock.sin_addr);
  88. std::cout << "[" << client_port << "-" << client_ip << "]" << std::endl;
  89. // version 2.1:多进程版
  90. pid_t pid = fork();
  91. if (pid == 0)
  92. {
  93. // 子进程
  94. if (fork() > 0)
  95. exit(0);
  96. // 孙子进程
  97. close(listensock_);
  98. service(serversock, client_ip, client_port);
  99. }
  100. // 父进程
  101. waitpid(pid, nullptr, 0);
  102. close(serversock);
  103. }
  104. }
  105. ~TcpServer()
  106. {
  107. close(listensock_);
  108. }
  109. private:
  110. int listensock_;
  111. std::string ip_;
  112. uint16_t port_;
  113. };

我们让子进程创建完孙子进程后立刻退出,此时服务进程(父进程)调用wait/waitpid函数等待子进程就能立刻等待成功,此后服务进程就能继续调用accept函数获取其他客户端的连接请求。

而由于子进程退出,孙子进程就变成孤儿进程,被os领养,最后由os自动回收。 

结果:

多线程版本:我们还可以创建新的线程去对客户端进行服务,让主线程继续获取连接:

  1. #include <iostream>
  2. #include <string>
  3. #include <cstring>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <cassert>
  11. #include <signal.h>
  12. static int gmv = 20;
  13. static void service(int sock, const std::string &clientip, const uint16_t &clientport)
  14. {
  15. char buffer[1024];
  16. while (true)
  17. {
  18. ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
  19. if (s < 0)
  20. {
  21. std::cout << "接收信息失败!" << std::endl;
  22. break;
  23. }
  24. else if (s > 0)
  25. {
  26. buffer[s] = 0;
  27. std::cout << clientip << ":" << clientport << std::endl;
  28. }
  29. else
  30. {
  31. std::cout << "客户端关闭!" << std::endl;
  32. break;
  33. }
  34. write(sock, buffer, strlen(buffer));
  35. }
  36. }
  37. class threaddata
  38. {
  39. public:
  40. int sock_;
  41. std::string ip_;
  42. uint16_t port_;
  43. };
  44. class TcpServer
  45. {
  46. public:
  47. static void *threadRountine(void *arg)
  48. {
  49. pthread_detach(pthread_self());
  50. threaddata *td = static_cast<threaddata *>(arg);
  51. service(td->sock_, td->ip_, td->port_);
  52. delete td;
  53. }
  54. TcpServer(const uint16_t port, const std::string &ip = "") : listensock_(-1), ip_(ip), port_(port)
  55. {
  56. }
  57. void initTcpServer()
  58. {
  59. // 1.创建套接字
  60. listensock_ = socket(AF_INET, SOCK_STREAM, 0);
  61. if (listensock_ < 0)
  62. {
  63. std::cout << "创建套接字失败!" << std::endl;
  64. exit(0);
  65. }
  66. // 2.进行绑定
  67. struct sockaddr_in src_server;
  68. bzero(&src_server, sizeof(src_server));
  69. src_server.sin_family = AF_INET;
  70. src_server.sin_port = htons(port_);
  71. inet_pton(AF_INET, ip_.c_str(), &src_server);
  72. socklen_t len = sizeof(src_server);
  73. if (bind(listensock_, (struct sockaddr *)&src_server, len) < 0)
  74. {
  75. std::cout << "绑定失败!" << std::endl;
  76. exit(1);
  77. }
  78. // 3.开始监听,等待连接
  79. if (listen(listensock_, gmv) < 0)
  80. {
  81. std::cout << "监听失败!" << std::endl;
  82. exit(2);
  83. }
  84. std::cout << "服务器初始化成功!" << std::endl;
  85. }
  86. void start()
  87. {
  88. while (true)
  89. {
  90. // 4.获取链接
  91. struct sockaddr_in client_sock;
  92. socklen_t len = sizeof(client_sock);
  93. int serversock = accept(listensock_, (struct sockaddr *)&client_sock, &len);
  94. if (serversock < 0)
  95. {
  96. std::cout << "获取链接失败!" << std::endl;
  97. exit(3);
  98. }
  99. // 5.开始通信服务
  100. uint16_t client_port = ntohs(client_sock.sin_port);
  101. std::string client_ip = inet_ntoa(client_sock.sin_addr);
  102. std::cout << "[" << client_port << "-" << client_ip << "]" << std::endl;
  103. // version 3——多线程版本
  104. pthread_t tid;
  105. threaddata *td = new threaddata();
  106. td->sock_ = serversock;
  107. td->ip_ = client_ip;
  108. td->port_ = client_port;
  109. pthread_create(&tid, nullptr, threadRountine, td);
  110. }
  111. }
  112. ~TcpServer()
  113. {
  114. close(listensock_);
  115. }
  116. private:
  117. int listensock_;
  118. std::string ip_;
  119. uint16_t port_;
  120. };

 

四、完整代码

tcp_server.hpp

  1. #include <iostream>
  2. #include <string>
  3. #include <cstring>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <cassert>
  11. #include <signal.h>
  12. static int gmv = 20;
  13. static void service(int sock, const std::string &clientip, const uint16_t &clientport)
  14. {
  15. char buffer[1024];
  16. while (true)
  17. {
  18. ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
  19. if (s < 0)
  20. {
  21. std::cout << "接收信息失败!" << std::endl;
  22. break;
  23. }
  24. else if (s > 0)
  25. {
  26. buffer[s] = 0;
  27. std::cout << clientip << ":" << clientport << std::endl;
  28. }
  29. else
  30. {
  31. std::cout << "客户端关闭!" << std::endl;
  32. }
  33. write(sock, buffer, strlen(buffer));
  34. }
  35. }
  36. class threaddata
  37. {
  38. public:
  39. int sock_;
  40. std::string ip_;
  41. uint16_t port_;
  42. };
  43. class TcpServer
  44. {
  45. public:
  46. static void *threadRountine(void *arg)
  47. {
  48. pthread_detach(pthread_self());
  49. threaddata *td = static_cast<threaddata *>(arg);
  50. service(td->sock_, td->ip_, td->port_);
  51. delete td;
  52. }
  53. TcpServer(const uint16_t port, const std::string &ip = "") : listensock_(-1), ip_(ip), port_(port)
  54. {
  55. }
  56. void initTcpServer()
  57. {
  58. // 1.创建套接字
  59. listensock_ = socket(AF_INET, SOCK_STREAM, 0);
  60. if (listensock_ < 0)
  61. {
  62. std::cout << "创建套接字失败!" << std::endl;
  63. exit(0);
  64. }
  65. // 2.进行绑定
  66. struct sockaddr_in src_server;
  67. bzero(&src_server, sizeof(src_server));
  68. src_server.sin_family = AF_INET;
  69. src_server.sin_port = htons(port_);
  70. inet_pton(AF_INET, ip_.c_str(), &src_server);
  71. socklen_t len = sizeof(src_server);
  72. if (bind(listensock_, (struct sockaddr *)&src_server, len) < 0)
  73. {
  74. std::cout << "绑定失败!" << std::endl;
  75. exit(1);
  76. }
  77. // 3.开始监听,等待连接
  78. if (listen(listensock_, gmv) < 0)
  79. {
  80. std::cout << "监听失败!" << std::endl;
  81. exit(2);
  82. }
  83. std::cout << "服务器初始化成功!" << std::endl;
  84. }
  85. void start()
  86. {
  87. signal(SIGCHLD, SIG_IGN);
  88. while (true)
  89. {
  90. // 4.获取链接
  91. struct sockaddr_in client_sock;
  92. socklen_t len = sizeof(client_sock);
  93. int serversock = accept(listensock_, (struct sockaddr *)&client_sock, &len);
  94. if (serversock < 0)
  95. {
  96. std::cout << "获取链接失败!" << std::endl;
  97. exit(3);
  98. }
  99. // 5.开始通信服务
  100. uint16_t client_port = ntohs(client_sock.sin_port);
  101. std::string client_ip = inet_ntoa(client_sock.sin_addr);
  102. std::cout << "[" << client_port << "-" << client_ip << "]" << std::endl;
  103. // version 1:单进程版服务————服务器一次只能处理一个客户端,只有处理完一个,才能处理下一个
  104. // service(serversock, client_ip, client_port);
  105. // version 2.0:多进程版本——创建子进程给新的连接提供服务,父进程去继续获取新的连接
  106. /* pid_t id = fork();
  107. assert(id != -1);
  108. if (id == 0)
  109. {
  110. // child 并且注意僵尸状态
  111. // child会继承父进程打开的文件及其fd,子进程不需要进行监听的套接字,关闭
  112. close(listensock_);
  113. //子进程只需要给连接客户端提供服务的套接字
  114. service(serversock, client_ip, client_port);
  115. exit(0);
  116. } */
  117. /* // version 2.1:多进程版
  118. pid_t pid = fork();
  119. if (pid == 0)
  120. {
  121. // 子进程
  122. if (fork() > 0)
  123. exit(0);
  124. // 孙子进程
  125. close(listensock_);
  126. service(serversock, client_ip, client_port);
  127. }
  128. // 父进程
  129. waitpid(pid, nullptr, 0); */
  130. // version 3——多线程版本
  131. pthread_t tid;
  132. threaddata *td = new threaddata();
  133. td->sock_ = serversock;
  134. td->ip_ = client_ip;
  135. td->port_ = client_port;
  136. pthread_create(&tid, nullptr, threadRountine, td);
  137. close(serversock);
  138. }
  139. }
  140. ~TcpServer()
  141. {
  142. close(listensock_);
  143. }
  144. private:
  145. int listensock_;
  146. std::string ip_;
  147. uint16_t port_;
  148. };

tcp_server.cc

  1. #include "tcp_server.hpp"
  2. #include <memory>
  3. static void usage(std::string proc)
  4. {
  5. std::cout << "\n"
  6. << proc << " port"
  7. << std::endl;
  8. }
  9. // ./tcpserver 8080
  10. int main(int argc, char *argv[])
  11. {
  12. if (argc != 2)
  13. {
  14. usage(argv[0]);
  15. exit(0);
  16. }
  17. uint16_t server_port=atoi(argv[1]);
  18. std::unique_ptr<TcpServer> sev(new TcpServer(server_port));
  19. sev->initTcpServer();
  20. sev->start();
  21. return 0;
  22. }

tcp_client.cc 

  1. #include <iostream>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. static void usage(std::string proc)
  9. {
  10. std::cout << "\n"
  11. << proc << " port"
  12. << std::endl;
  13. }
  14. // ./tcpclient IP port
  15. int main(int argc, char *argv[])
  16. {
  17. if (argc != 3)
  18. {
  19. usage(argv[0]);
  20. exit(1);
  21. }
  22. std::string server_ip = argv[1];
  23. uint16_t server_port = atoi(argv[2]);
  24. int sock = socket(AF_INET, SOCK_STREAM, 0);
  25. if (sock < 0)
  26. {
  27. std::cout << "创建套接字失败!" << std::endl;
  28. exit(0);
  29. }
  30. struct sockaddr_in server;
  31. memset(&server, 0, sizeof server);
  32. server.sin_family = AF_INET;
  33. server.sin_port = htons(server_port);
  34. server.sin_addr.s_addr = inet_addr(server_ip.c_str());
  35. if (connect(sock, (struct sockaddr *)&server, sizeof server) < 0)
  36. {
  37. std::cout << "连接失败!" << std::endl;
  38. exit(0);
  39. }
  40. // 开始通信
  41. while (true)
  42. {
  43. std::string line;
  44. std::cout << "请输入# ";
  45. std::getline(std::cin, line);
  46. ssize_t s = write(sock, line.c_str(), line.size());
  47. char buffer[1024];
  48. ssize_t m = read(sock, buffer, sizeof buffer - 1);
  49. buffer[m] = 0;
  50. std::cout << "服务器:" << buffer << std::endl;
  51. }
  52. return 0;
  53. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/554119
推荐阅读
相关标签
  

闽ICP备14008679号