网络编程-连接、发送、接收数据学习
1、概述
连接服务器、向服务器发数据、接受服务器数据,代码你能编写出来么?
2、详见代码(vs编译)
main.cpp
#include "NetSocket.h"
#include <string>
#include <iostream>
using namespace std;
int main() {// 连接服务器const char* ip = "192.168.202.223";int port = 8082;int connect_timeout = 10;bool flag = NetSocket::GetInstance().ConnectServer(ip, port, connect_timeout);cout << "connect flag:" << flag << endl;// 发送数据std::string sendData = "sendData 123456";int send_timeout = 10;flag = NetSocket::GetInstance().SendData(sendData.c_str(), sendData.length(), send_timeout);cout << "send data flag:" << flag << endl;// 收数据char recvbuf[512] = { 0 };// recvBytes实际项目中应该是包头或包体的长度int recvBytes = sendData.length();int recv_timeout = 10;flag = NetSocket::GetInstance().RecvData(recvbuf, recvBytes, recv_timeout);cout << "recv data flag:" << flag << endl;cout << "recv data:" << recvbuf << endl;return 0;
}
NetSocket.h
#ifndef NET_SOCKET_H_
#define NET_SOCKET_H_ 1class NetSocket
{
private:NetSocket();~NetSocket();NetSocket(const NetSocket& s) = delete;NetSocket& operator=(const NetSocket& s) = delete;public:static NetSocket& GetInstance();// 连接服务器bool ConnectServer(const char* ip, const int port, int timeout = 10);bool SendData(const char* buf, int bufLen, int timeout = 30);bool RecvData(char* buf, int bufLen, int timeout = 30);void CloseConnect();private:bool InitSocket();void UnInitSocket();int m_socket;bool m_bConnected;
};#endif
NetSocket.cpp
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Winsock2.h>
#include "NetSocket.h"
#include <ctime>
#include <string>
#pragma comment(lib, "Ws2_32.lib")NetSocket::NetSocket() :m_socket(INVALID_SOCKET),m_bConnected(false)
{InitSocket();
}NetSocket::~NetSocket()
{UnInitSocket();
}NetSocket& NetSocket::GetInstance()
{static NetSocket s;return s;
}bool NetSocket::ConnectServer(const char* ip, const int port, int timeout)
{m_socket = socket(AF_INET, SOCK_STREAM, 0);if (m_socket == INVALID_SOCKET){return false;}// 设置NoDelaylong noDelay = 1;setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, (LPSTR)&noDelay, sizeof(long));// 设置非阻塞 1非阻塞 0阻塞u_long mode = 1;int ret = ::ioctlsocket(m_socket, FIONBIO, &mode);if (ret != 0){return false;}struct sockaddr_in addrSrv = { 0 };addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(u_short(port));addrSrv.sin_addr.s_addr = inet_addr(ip);ret = connect(m_socket, (sockaddr*)&addrSrv, sizeof(addrSrv));if (ret == 0){m_bConnected = true;return true;}else if (ret == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK){return false;}// 用io复用函数select,判断sockfd状态int maxfd = m_socket + 1;fd_set write_fd;FD_ZERO(&write_fd);FD_SET(m_socket, &write_fd);// 1、null:没有事件永久阻塞// 2、毫秒、微秒都设置0:扫描下是否有信号,都立刻返回// 3、毫秒、微秒大于0:等待指定时间超时3struct timeval tv = {timeout, 0};int activity = ::select(maxfd, NULL, &write_fd, NULL, &tv);if (activity <= 0){return false;}if (FD_ISSET(m_socket, &write_fd)){m_bConnected = true;return true;}return false;
}bool NetSocket::SendData(const char* buf, int bufLen, int timeout)
{if (!m_bConnected){return false;}int ret = 0;int nSendBytes = 0;auto start_time = ::time(nullptr);while (true){ret = send(m_socket, buf + nSendBytes, bufLen - nSendBytes, 0);if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK){// tcp窗口太小发不出去,并且没有超时,继续等待if (::time(nullptr) - start_time < timeout){// 等待1毫秒,看看内核缓冲区是否有空间::Sleep(1);continue;}else{CloseConnect();return false;}}else if (ret < 1){// 出错了, 关闭连接CloseConnect();return false;}nSendBytes += ret;if (nSendBytes >= bufLen){return true;}// 防止CPU空转::Sleep(1);}return false;
}bool NetSocket::RecvData(char* buf, int bufLen, int timeout)
{if (!m_bConnected){return false;}int ret = 0;int nRecvBytes = 0;auto start_time = ::time(nullptr);while (true){ret = recv(m_socket, buf + nRecvBytes, bufLen - nRecvBytes, 0);if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK){if (::time(nullptr) - start_time < timeout){::Sleep(1);continue;}else{// 出错了,关闭连接CloseConnect();return false;}}else if (ret < 1){// 对端关闭连接了CloseConnect();return false;}nRecvBytes += ret;if (nRecvBytes >= bufLen){return true;}}return false;
}void NetSocket::CloseConnect()
{if (m_socket == INVALID_SOCKET){return;}closesocket(m_socket);m_socket = INVALID_SOCKET;m_bConnected = false;
}bool NetSocket::InitSocket()
{WORD wVersionRequested = MAKEWORD(2, 2);WSADATA wsaData;int nErrorID = ::WSAStartup(wVersionRequested, &wsaData);if (nErrorID != 0)return FALSE;if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){UnInitSocket();return FALSE;}return TRUE;
}void NetSocket::UnInitSocket()
{CloseConnect();::WSACleanup();
}
学习链接:https://github.com/0voice