整理socket编程<一>:win32 socket简易服务器开发

来源:互联网 发布:转录组数据上传 编辑:程序博客网 时间:2024/05/12 01:39

1.功能

windows下实现socket的简易服务器开发,接收来自于客户端的连接和业务请求,并给出响应。

2.原理

当然在进行socket编程时,要首先初始化socket环境

//初始化winsock环境WSAData wsa_data;WORD ver =MAKEWORD(2, 2);if(WSAStartup(ver, &wsa_data) != 0){std::cout << "初始化winsock环境失败" << std::endl;return -1;}

对应的清理socket环境

WSACleanup();

3.服务器实现

实现一个同步服务器,通过winsock2和ws2_32.lib,利用boost::threadgroup(线程池)实现较为高效的处理,阻塞模式,主线程负责接收客户端的连接请求,子线程负责socket业务通信

#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};while(true){int ret_size = recv(con_socket, szMessage, 1024, 0);if ( (ret_size == 0) || (ret_size == SOCKET_ERROR) ){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;}//创建socketSOCKET listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (listen_sock == INVALID_SOCKET){std::cout << "创建socket失败" << 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;while(true){connect_sock = accept(listen_sock, (LPSOCKADDR)&remote_addr, &addr_len);if (connect_sock == INVALID_SOCKET){std::cout << "connect failed!" << 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();//关闭连接closesocket(listen_sock);WSACleanup();return 0;}

4.简易客户端实现

#include "stdafx.h"#include <winsock2.h>#include <iostream>#pragma comment(lib, "WS2_32.lib")int _tmain(int argc, _TCHAR* argv[]){//初始化winsock环境WSAData wsa_data;WORD ver =MAKEWORD(2, 2);if(WSAStartup(ver, &wsa_data) != 0){std::cout << "初始化winsock环境失败" << std::endl;return -1;}//创建socketSOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (client_socket == INVALID_SOCKET){std::cout << "创建socket失败" << std::endl;return -1;}//远程服务器信息sockaddr_in server_addr;memset(&server_addr, 0, sizeof(sockaddr_in));server_addr.sin_family = AF_INET;server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");server_addr.sin_port = htons(2000);//连接远程服务器int ret = connect(client_socket, (sockaddr *)&server_addr, sizeof(server_addr));if (ret == SOCKET_ERROR){std::cout << "连接远程服务器失败" << std::endl;return -1;}const int MESSAGE_SIZE = 1024;char szMessage[MESSAGE_SIZE] = {0};while (true){int receive_ret = recv(client_socket, szMessage, MESSAGE_SIZE, 0);std::cout << "收取到[" << receive_ret << "]字节:" << szMessage << std::endl;std::cout << "send::" << std::endl;gets_s(szMessage);size_t message_len = strlen(szMessage);int send_ret = send(client_socket, szMessage, message_len, 0);if (send_ret != message_len){std::cout << "发送数据失败" << std::endl;return -1;}}closesocket(client_socket);WSACleanup();return 0;}
客户端实现比较简单,连接的是本地的服务器。

5.总结

上面是我自己实现的一个简单的TCP服务器和客户端的demo,不过里面使用了现在主流的同步服务器的实现机制,即连接和业务分离,当处理大量的并发连接时,需要使用I/O复用模型,同时监听多个I/O端口,可以参考下某位大牛的这篇文章:http://blog.csdn.net/hguisu/article/details/7453390




1 0
原创粉丝点击