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_ 1
class 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;
}
// 设置NoDelay
long 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:等待指定时间超时3
struct 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