当前位置:   article > 正文

C++socket编程学习总结(2)(发送信息send函数、recv函数与多线程实现多个用户同时连接)_c++ recv函数

c++ recv函数

今天接着昨天的学习来,昨天我复习了简单的TCP服务器的创建、绑定端口号、监听并接收信息,还有大端(网络字节流)小端(X86架构CPU使用的字节流)的概念。

今天复习发送信息send函数、recv函数与多线程实现多个用户同时连接。send函数用于发送一段数据,recv函数用于接收数据。

如下所示:

  1. char buf[1024];//接收信息的最大长度,记位buf
  2. memset(buf, 1024, 0);
  3. while(true)
  4. {
  5. int recvlen = recv(client, buf, sizeof(buf) - 1, 0);//windows没有read函数,linux才有
  6. if (recvlen <= 0)break;//没有收到
  7. buf[recvlen] = '\0';
  8. if (strstr(buf, "q") != NULL)//按q退出
  9. {
  10. char re[] = "quit success!!!\n";
  11. send(client, re, strlen(re) + 1, 0);//加1是因为还有\0
  12. break;
  13. }
  14. int sendlen = send(client, "ok\n", 3, 0);//linux可以使用write
  15. cout << "RECEIVE:" << buf << endl;
  16. cout << "len:" << recvlen << endl;
  17. //len是接收数据的实际大小,len<=buf长度(这里是1024)
  18. }

 与昨天的代码连在一块这才是完整的代码,功能比较简单,当用户键入q时候退出连接但不知道为什么只能一次读取一个字符,盲猜是unicode编码问题,使得自动添加\0:

这是完整代码:

  1. #include <iostream>
  2. #include<thread>
  3. #include<ws2tcpip.h>
  4. #include<Windows.h>
  5. #include<string>
  6. #include<string.h>
  7. using namespace std;
  8. int main(int argc, char* argv[])
  9. {
  10. //初始化动态链接库
  11. WSADATA ws;
  12. WSAStartup(MAKEWORD(2, 2), &ws);//22是版本号,加载动态链接库
  13. int sock = socket(AF_INET, SOCK_STREAM, 0);//AF_INET指明调用TCP/IP协议,SOCK_STREAM是TCP的协议(相对于UDP来讲)
  14. cout << sock << endl;//打印句柄id,失败返回负值
  15. //失败提示
  16. if (sock == -1)
  17. {
  18. cout << "create socket failed!" << endl;
  19. return -1;
  20. }
  21. //测试端口号
  22. unsigned short port = 8080;
  23. if (argc > 1)
  24. {
  25. port = atoi(argv[1]);
  26. }
  27. //创建TCP相关的结构体
  28. sockaddr_in saddr;
  29. saddr.sin_family = AF_INET;//使用TCP
  30. saddr.sin_port = htons(port);//本地字节序转网络字节序
  31. //X86架构是小端的而网络字节流是大端的,
  32. //Linux不一定,小型linux使用的也是和网路字节序一样的话转换也只是一个空的宏,
  33. //这时候会可有可无,但考虑兼容性要求建议加上
  34. saddr.sin_addr.s_addr = htonl(0);//这里可以指定网卡,0是任意的意思
  35. if (bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0)//绑定端口号到上面创建的socket,并判断是否成功
  36. {
  37. cout << "bind port " << port << " failed!" << endl;
  38. return -2;
  39. }
  40. else
  41. {
  42. cout << "bind port " << port << " success!" << endl;
  43. }
  44. listen(sock, 10);//监听,接受连接;10是列表大小,套接字接收队列的最大大小
  45. //accept每调用一次队列就会减少一个
  46. sockaddr_in caddr;
  47. socklen_t len = sizeof(caddr);
  48. int client = accept(sock, (sockaddr*)&caddr, &len);//取信息
  49. cout << client << endl;
  50. char* ip = inet_ntoa(caddr.sin_addr);
  51. unsigned short cport = ntohs(caddr.sin_port);//网络字节序转本地字节序
  52. cout << "client ip is " << ip << " port is " << cport << endl;
  53. char buf[1024];//接收信息的最大长度,记位buf
  54. memset(buf, 1024, 0);
  55. while(true)
  56. {
  57. int recvlen = recv(client, buf, sizeof(buf) - 1, 0);//windows没有read函数,linux才有
  58. if (recvlen <= 0)break;//没有收到
  59. buf[recvlen] = '\0';
  60. if (strstr(buf, "q") != NULL)//按q退出
  61. {
  62. char re[] = "quit success!!!\n";
  63. send(client, re, strlen(re) + 1, 0);//加1是因为还有\0
  64. break;
  65. }
  66. int sendlen = send(client, "ok\n", 3, 0);//linux可以使用write
  67. cout << "RECEIVE:" << buf << endl;
  68. cout << "len:" << recvlen << endl;
  69. //len是接收数据的实际大小,len<=buf长度(这里是1024)
  70. }
  71. closesocket(client);//关闭连接
  72. return 0;
  73. }

当是这个时候只能有一个用户接入,这时候得用多线程来解决问题,我使用了C++11的标准库thread。

先定义一个类tcpshread,然后每有一个用户连接那就new一个Tcpthread,如下:

  1. class tcpthread
  2. {
  3. public:
  4. void Main()
  5. {
  6. char buf[1024] = { 0 };//接收信息的最大长度,记位buf
  7. while (true)
  8. {
  9. int recvlen = recv(client, buf, sizeof(buf) - 1, 0);//windows没有read函数,linux才有
  10. if (recvlen <= 0)break;//没有收到
  11. if (strstr(buf, "q") != NULL)//按q退出
  12. {
  13. char re[] = "quit success!!!\n";
  14. send(client, re, strlen(re) + 1, 0);//加1是因为还有\0
  15. break;
  16. }
  17. int sendlen = send(client, "ok\n", 3, 0);//linux可以使用write
  18. cout << "receive:" << buf << endl;
  19. //len是接收数据的实际大小,len<=buf长度(这里是1024)
  20. }
  21. closesocket(client);//关闭连接
  22. }
  23. int client = 0;
  24. };

这是完整代码:

  1. #include <iostream>
  2. #include<thread>
  3. #include<ws2tcpip.h>
  4. #include<Windows.h>
  5. #include<string>
  6. #include<string.h>
  7. using namespace std;
  8. class tcpthread
  9. {
  10. public:
  11. void Main()
  12. {
  13. char buf[1024] = { 0 };//接收信息的最大长度,记位buf
  14. while (true)
  15. {
  16. int recvlen = recv(client, buf, sizeof(buf) - 1, 0);//windows没有read函数,linux才有
  17. if (recvlen <= 0)break;//没有收到
  18. if (strstr(buf, "q") != NULL)//按q退出
  19. {
  20. char re[] = "quit success!!!\n";
  21. send(client, re, strlen(re) + 1, 0);//加1是因为还有\0
  22. break;
  23. }
  24. int sendlen = send(client, "ok\n", 3, 0);//linux可以使用write
  25. cout << "receive:" << buf << endl;
  26. //len是接收数据的实际大小,len<=buf长度(这里是1024)
  27. }
  28. closesocket(client);//关闭连接
  29. }
  30. int client = 0;
  31. };
  32. int main(int argc, char* argv[])
  33. {
  34. //初始化动态链接库
  35. WSADATA ws;
  36. WSAStartup(MAKEWORD(2, 2), &ws);//22是版本号,加载动态链接库
  37. int sock = socket(AF_INET, SOCK_STREAM, 0);//AF_INET指明调用TCP/IP协议,SOCK_STREAM是TCP的协议(相对于UDP来讲)
  38. cout << sock << endl;//打印句柄id,失败返回负值
  39. //失败提示
  40. if (sock == -1)
  41. {
  42. cout << "create socket failed!" << endl;
  43. return -1;
  44. }
  45. //测试端口号
  46. unsigned short port = 8080;
  47. if (argc > 1)
  48. {
  49. port = atoi(argv[1]);
  50. }
  51. //创建TCP相关的结构体
  52. sockaddr_in saddr;
  53. saddr.sin_family = AF_INET;//使用TCP
  54. saddr.sin_port = htons(port);//本地字节序转网络字节序
  55. //X86架构是小端的而网络字节流是大端的,
  56. //Linux不一定,小型linux使用的也是和网路字节序一样的话转换也只是一个空的宏,
  57. //这时候会可有可无,但考虑兼容性要求建议加上
  58. saddr.sin_addr.s_addr = htonl(0);//这里可以指定网卡,0是任意的意思
  59. if (bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0)//绑定端口号到上面创建的socket,并判断是否成功
  60. {
  61. cout << "bind port " << port << " failed!" << endl;
  62. return -2;
  63. }
  64. else
  65. {
  66. cout << "bind port " << port << " success!" << endl;
  67. }
  68. listen(sock, 10);//监听,接受连接;10是列表大小,套接字接收队列的最大大小
  69. //accept每调用一次队列就会减少一个
  70. while(true)
  71. {
  72. sockaddr_in caddr;
  73. socklen_t len = sizeof(caddr);
  74. int client = accept(sock, (sockaddr*)&caddr, &len);//取信息
  75. if (client <= 0)break;
  76. cout << client << endl;
  77. char* ip = inet_ntoa(caddr.sin_addr);
  78. unsigned short cport = ntohs(caddr.sin_port);//网络字节序转本地字节序
  79. cout << "client ip is " << ip << " port is " << cport << endl;
  80. tcpthread *th = new tcpthread();
  81. th->client = client;
  82. thread sth(&tcpthread::Main, th);
  83. sth.detach();//释放主线程拥有的子线程的资源
  84. }
  85. closesocket(sock);
  86. return 0;
  87. }

测试结果图:


END

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

闽ICP备14008679号