一个简易TCP服务器的多种实现

来源:互联网 发布:hp1010墨盒清零软件 编辑:程序博客网 时间:2024/05/01 14:56

作为对上一篇文章的相关代码补充点击打开链接

#include "stdafx.h"#include <WinSock2.h>#include <iostream>#include <MSTCPiP.h>//#define BOOST_ALL_DYN_LINK//使用动态库链接#include <boost/thread.hpp>#include <boost/bind.hpp>#include <boost/asio.hpp>#include <boost/smart_ptr.hpp>#pragma comment(lib,"WS2_32.lib")void handle_msg(SOCKET con_socket){if (con_socket == INVALID_SOCKET){return;}char server_text[] = "TCP server demo!";char szMessage[1024] = {0};send(con_socket, server_text, strlen(server_text), 0);int errorcode;while(true){int ret_size = recv(con_socket, szMessage, 1024, 0);if ( (ret_size == 0) || (ret_size == SOCKET_ERROR) ){errorcode = WSAGetLastError();if (errorcode == WSAEWOULDBLOCK){std::cout << "等待接收数据" << std::endl;Sleep(1000);continue;}else{printf("Client has closed the connection\n"); return;}}else{szMessage[ret_size] = '\0';std::cout << boost::this_thread::get_id() << "接收到数据:" << szMessage <<std::endl;}send(con_socket, server_text, strlen(server_text), 0);}}//同步服务器,利用winsock2和ws2_32.lib,利用boost::threadgroup(线程池)实现较为高效的处理,阻塞模式,主线程负责接收客户端的连接请求,子线程负责socket业务通信int SyncSocketSvr() {WSADATA     wsaData;//初始化socket环境if(WSAStartup(0x0202, &wsaData) != 0){std::cout << "初始化socket lib环境失败" << std::endl;return -1;}//创建socket,默认是阻塞的SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (listen_sock == INVALID_SOCKET){std::cout << "创建socket失败" << std::endl;return -1;}//将socket设置为非阻塞模式int iMode = 1; //0:阻塞if (ioctlsocket(listen_sock, FIONBIO, (u_long FAR*) &iMode) == SOCKET_ERROR)//非阻塞设置{std::cout << "set asyn I/O失败!" << std::endl;return -1;}//初始化服务器的IP地址sockaddr_in server_addr;memset(&server_addr, 0, sizeof(sockaddr_in));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htonl(INADDR_ANY);server_addr.sin_port = htons(2000);//绑定IP到socket上if(bind(listen_sock, (LPSOCKADDR)&server_addr, sizeof(server_addr)) == SOCKET_ERROR){std::cout << "bind failed!" << std::endl;return -1;}//开启监听if (listen(listen_sock, 3) == SOCKET_ERROR){std::cout << "listen failed" << std::endl;}//循环接收客户端的连接请求sockaddr_in remote_addr;memset(&remote_addr, 0, sizeof(sockaddr_in));int addr_len = sizeof(sockaddr_in);SOCKET connect_sock;char server_text[] = "TCP server demo!";boost::thread_group tg;int errorcode;fd_set listen_set;timeval time_out;while(true){FD_ZERO(&listen_set);//初始化set集合FD_SET(listen_sock, &listen_set);//设置set集合time_out.tv_sec = 1;time_out.tv_usec = 0;int ret = select(0, &listen_set, NULL, NULL, &time_out);if (ret <= 0){if (ret < 0){std::cout << "监听时select返回错误:" << WSAGetLastError() << std::endl;}elsecontinue;//超时}if (FD_ISSET(listen_sock, &listen_set))//listen_sock是不是有可读数据{connect_sock = accept(listen_sock, (LPSOCKADDR)&remote_addr, &addr_len);if (connect_sock == INVALID_SOCKET){errorcode = WSAGetLastError();if (errorcode == WSAEWOULDBLOCK)//表示没有客户端发起连接,继续循环  {Sleep(100);continue;}else{std::cout << "connect failed!" << std::endl;return -1;}}//将socket设置为非阻塞模式int con_Mode = 1; //0:阻塞if (ioctlsocket(connect_sock, FIONBIO, (u_long FAR*) &con_Mode) == SOCKET_ERROR)//非阻塞设置{std::cout << "set asyn I/O失败!" << std::endl;return -1;}std::cout << "接收到一个连接请求,IP:" << inet_ntoa(remote_addr.sin_addr) << std::endl;//主流做法:创建一个子线程,绑定这个socket,负责此socket上的所有通信,或者采用线程池tg.create_thread(boost::bind(handle_msg, connect_sock));}}tg.join_all();//关闭连接,延时5秒直接关闭,原来的closesocket后,socket处于time_wait状态,不能立即复用,下面的方法是等待5秒后,直接释放可以复用//SO_LINGER将决定系统如何处理残存在套接字发送队列中的数据struct linger{u_short l_onoff;u_short l_linger;};linger m_linger;m_linger.l_onoff = 1;m_linger.l_linger = 5;//若为0,直接丢弃setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (const char*)&m_linger, sizeof(m_linger));//setsockopt(listen_sock, SOL_SOCKET, SO_DONTLINGER, (const char*)&m_linger, sizeof(m_linger));closesocket(listen_sock);WSACleanup();return 0;}


0 0
原创粉丝点击