Windows套接字I/O模型(1) -- 阻塞模型
来源:互联网 发布:工业机器人用什么编程 编辑:程序博客网 时间:2024/06/06 20:31
套接字I/O的阻塞模型是最常见的,也是进行socket编程时最早接触的一个模型。因为它是阻塞的,所以一般都会结合线程一起使用(如将accept
,recv
等放到单独的线程),防止阻塞主线程。下面的示例只演示了基本都流程,并没有请其放到独立的线程中执行。
一、服务端
服务端大致流程:
1. 创建Socket
2. Bind端口
3. 开始Listen
4. accept客户端连接(一般在子线程中不间断accept)
5. send数据到客户端(也可以recv)
6. close socket
#include <winsock2.h>#include <iostream>#include <assert.h>using namespace std;#pragma comment(lib, "Ws2_32.lib")const u_short kPort = 10001;const std::string kHelloServer = "hello, I'm server.";int main(){ WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); SOCKET socket_ = INVALID_SOCKET; SOCKET s_ = INVALID_SOCKET; do { // (1) socket_ = ::socket(AF_INET, SOCK_STREAM, 0); if (socket_ == INVALID_SOCKET) { std::cout << "create socket failed, GLE: " << WSAGetLastError() << std::endl; break; } // (2) struct sockaddr_in addr = { 0 }; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(kPort); if (bind(socket_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR) { std::cout << "bind failed, GLE: " << WSAGetLastError() << std::endl; break; } // (3) if (listen(socket_, 5) == SOCKET_ERROR) { std::cout << "listen failed, GLE: " << WSAGetLastError() << std::endl; break; } std::cout << "listen on port: " << kPort << std::endl; // (4) while (true) { struct sockaddr_in addr_c = { 0 }; int addr_len = sizeof(addr_c); SOCKET s = accept(socket_, reinterpret_cast<sockaddr*>(&addr_c), &addr_len); if (s == SOCKET_ERROR) { std::cout << "accept failed, GLE: " << WSAGetLastError() << std::endl; break; } std::cout << "new connection" << endl; // (5) // 此处使用while循环send,详见 三、流协议 int left = kHelloServer.length(); int idx = 0; while (left > 0) { int err = send(s, (const char*)(kHelloServer.c_str() + idx), left, 0); if (err == SOCKET_ERROR) { std::cout << "send failed, GLE: " << WSAGetLastError() << std::endl; break; } left -= err; idx += err; std::cout << "bytes sent: " << err << std::endl; } } } while (false); // (6) closesocket(socket_); closesocket(s_); WSACleanup(); return 0;}
二、客户端
客户端大致流程:
1. 创建Socket
2. connect服务端
3. recv接收数据从服务端(也可以send)
4. close socket
#include <iostream>#include <winsock2.h>#include <assert.h>#pragma comment(lib, "Ws2_32.lib")const std::string kIP = "127.0.0.1";const u_short kPort = 10001;const std::string kHelloClient = "hello, I'm client.";int main(){ WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); SOCKET socket_ = INVALID_SOCKET; do { // (1) socket_ = ::socket(AF_INET, SOCK_STREAM, 0); if (socket_ == INVALID_SOCKET) { std::cout << "create socket failed, GLE: " << WSAGetLastError() << std::endl; break; } // (2) struct sockaddr_in addr = { 0 }; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(kIP.c_str()); addr.sin_port = htons(kPort); if (connect(socket_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR) { std::cout << "connect failed, GLE: " << WSAGetLastError() << std::endl; break; } // (3) char buf[100] = { 0 }; int err = recv(socket_, buf, 100, 0); if (err > 0) { std::cout << "recv: " << buf << std::endl; } else if (err == 0) { std::cout << "connection closed." << std::endl; break; } else { std::cout << "recv failed, GLE: " << WSAGetLastError() << std::endl; break; } } while (false); // (4) closesocket(socket_); WSACleanup(); return 0;}
三、流协议
由于大多数面向连接的协议(如TCP)也是流协议。在流协议中,发送者和接收者可以将数据分解成小块数据,或将数据合并成大块数据。对于流套接字上收发数据所有用的函数(如send, recv),需要知道的是:它们不能保证要求进行读取或写入的数据量。比如用send发送一个有1024字节的字符缓冲区时,send函数可能返回的已发出的字节数少于1024。因为对每个收发数据的套接字来说,系统都为它们分配了充足的缓冲区空间,所以send的返回值将被设为已经发送的字节数。
针对这种情况,要保证缓冲区所有数据都被发送出去,可以采用下面的代码:
int left = kHelloServer.length();int idx = 0;while (left > 0) { int err = send(s, (const char*)(kHelloServer.c_str() + idx), left, 0); if (err == SOCKET_ERROR) { std::cout << "send failed, GLE: " << WSAGetLastError() << std::endl; break; } left -= err; idx += err; std::cout << "bytes sent: " << err << std::endl;}
对于接收数据来说,也可以采用上面的方式,但意义不大,因为我们一般都是循环的、不间断的接收数据,很少有上面的例子中的,只接收一次的情况。
阅读全文
0 0
- Windows套接字I/O模型(1) -- 阻塞模型
- windows套接字I/O模型之——阻塞模型(1)
- Windows套接字I/O模型(2) -- Select模型
- Windows套接字I/O模型(3) -- WSAAsyncSelect模型
- Windows套接字I/O模型(4) -- WSAEventSelect模型
- windows套接字I/O模型之——阻塞模型(2)
- Windows套接字I/O模型
- Windows套接字I/O 模型
- Windows 套接字I/O 模型
- windows套接字I/O模型
- Windows 套接字I/O 模型
- Windows套接字I/O模型
- Windows套接字I/O模型(1) 套接字模式
- Windows套接字I/O模型之套接字模式
- 套接字i/o模型
- 套接字I/O模型
- 套接字I/O模型
- 套接字I/O模型
- JavaSpark-编程进阶-累加器
- Service: Amazon S3; Status Code: 500; Error Code: InternalError; Request ID: 1512961051843
- Unity配合SQLite开发数据库注意事项
- java嵌套类
- 2018年,每个有追求的设计师都需要面对6个挑战
- Windows套接字I/O模型(1) -- 阻塞模型
- ZkClient之创建节点。
- luoguP3377 【模板】左偏树(可并堆)
- Linux 2.6 CFS 调度算法内幕
- 这3种独特的趋势,能让网页设计增色不少
- [BZOJ3261]-可持久化trie
- leetcode 417. Pacific Atlantic Water Flow 一个很经典的DFS深度优先遍历做法
- 幸运大奖
- 产品经理内功修炼——需求