C++ —— 网络通信
之前在Linux系统下介绍了多种实现网络通信的方式,从本文开始后面的文章将在Windows系统下用C++为大家介绍技术,敬请期待~。
话不多说,直接进入正文,我们知道,要完成网络通信要用到非常多的函数,并且函数的参数比较复杂,所以小编在想封装一个network的工具方便后面要写通信的时候直接调用。工具包括一个头文件network.h和一个 .cpp 文件network.cpp。头文件中定义一个NetWork类,成员变量包含了通信要用到的诸如描述符和通信地址的信息;成员函数就是通信过程中用到的函数。
network.h头文件如下:
#ifndef NETWORK_H
#define NETWORK_H
#include <iostream>
#include <sys/types.h>
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
class NetWork
{
int sock; //socket对象描述符
int type; //协议类型
sockaddr_in addr; //通信地址
socklen_t addrlen; //地址结构字节数
bool is_svr; //是否为服务器端
public:
NetWork(void);
NetWork(int type,const char *ip,short port,bool is_svr=false);
~NetWork(void);
bool open(void);
NetWork* accept(void);
int send(const char *buf,int flag=0);
int send(const void *buf,size_t len,int flag=0);
int recv(void *buf,size_t len,int flag=0);
};
#endif // NETWORK_H
下面要在network.cpp文件中去一一定义NetWork的成员函数,也是工具的主要逻辑所在。为了通用性考虑,我们在NetWork类中专门定义了协议类型type去区分TCP通信和UDP通信协议以及定义了is_svr去区分调用服务器端和客户端,并在函数定义中去判断从而不影响各自的网络通信步骤。
#include "network.h"
using namespace std;
NetWork::NetWork(void)
{
addrlen = sizeof(addr);
type = SOCK_STREAM;
is_svr = false;
}
NetWork::NetWork(int type, const char *ip, short port, bool is_svr):type(type), is_svr(is_svr)
{
// 不在构造函数中创建socket,因为socket创建可能失败,而构造函数是没有返回值的,不能在此创建
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
addrlen = sizeof(addr);
}
NetWork::~NetWork(void)
{
close(sock);
}
bool NetWork::open(void)
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
perror("WSADATA失败");
}
//创建socket对象
sock = socket(AF_INET, type, 0);
if (sock < 0)
{
perror("socket");
return false;
}
//根据type和is_svr执行以下流程
if(is_svr)
{
if(bind(sock, (sockaddr*)&addr, addrlen))
{
perror("bind");
return false;
}
if(SOCK_STREAM == type && listen(sock, 50))
{
perror("listen");
return false;
}
}
else if(SOCK_STREAM == type && connect(sock, (sockaddr*)&addr, addrlen))
{
perror("connect");
return false;
}
return true;
}
NetWork *NetWork::accept(void)
{
if(SOCK_STREAM!= type || !is_svr)
{
puts("只有type为SOCK_STREAM且为服务端才能调用该函数\n");
return NULL;
}
NetWork *nw = new NetWork;
nw->sock = ::accept(sock, (sockaddr*)&nw->addr, &nw->addrlen);
if(nw->sock < 0)
{
perror("accept");
delete nw;
return NULL;
}
return nw;
}
int NetWork::send(const char *buf, int flag)
{
if(SOCK_STREAM == type)
return ::send(sock, buf, strlen(buf)+1, flag);
else
return sendto(sock, buf, strlen(buf)+1, flag, (sockaddr*)&addr, addrlen);
}
int NetWork::send(const void *buf, size_t len, int flag)
{
if(SOCK_STREAM == type)
return ::send(sock, (const char*)buf, len, flag);
else
return sendto(sock, (const char*)buf, len, flag, (sockaddr*)&addr, addrlen);
}
int NetWork::recv(void *buf, size_t len, int flag)
{
if(SOCK_STREAM == type)
return ::recv(sock, (char*)buf, len, flag);
else
return recvfrom(sock, (char*)buf, len, flag, (sockaddr*)&addr, &addrlen);
}
为了测试工具是否具备以上介绍的功能,我们准备一个TCP客户端和一个服务器进行通信以进行验证:
服务端:
#include "network.h"
using namespace std;
#define BUF_SIZE (4096)
void *run(void *arg)
{
NetWork *cnw = static_cast<NetWork *>(arg);
char *buf = new char[BUF_SIZE];
while (1)
{
int ret = cnw->recv(buf, BUF_SIZE);
if (ret <= 0 || 0 == strcmp(buf, "quit"))
{
puts("客户端退出!\n");
delete cnw;
delete buf;
return NULL;
}
printf("recv:%s bits:%d\n", buf, ret);
strcat(buf, ":return");
ret = cnw->send(buf);
if (ret <= 0)
{
puts("客户端退出!\n");
delete cnw;
delete buf;
return NULL;
}
}
}
int main(int argc, const char *argv[])
{
if (3 != argc)
{
printf("User: server <ip> <port>");
return 0;
}
// WSADATA wsaData;
// if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
// {
// perror("WSADATA失败");
// }
NetWork *snw = new NetWork(SOCK_STREAM, argv[1], atoi(argv[2]), true);
if (!snw->open())
{
delete snw;
return -1;
}
while (1)
{
NetWork *cnw = snw->accept();
if (NULL == cnw)
{
continue;
}
pthread_t tid;
pthread_create(&tid, NULL, run, (void *)cnw);
}
return 0;
}
客户端:
#include "network.h"
using namespace std;
int main(int argc, const char *argv[])
{
// WSADATA wsaData;
// if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
// {
// perror("WSADATA失败");
// }
NetWork *cnw = new NetWork(SOCK_STREAM, argv[1], atoi(argv[2]), false);
if (!cnw->open())
{
delete cnw;
return -1;
}
char buf[4096];
size_t buf_size = sizeof(buf);
while (1)
{
cout << ">>>>>" << endl;
cin.getline(buf, buf_size);
int ret = cnw->send(buf, strlen(buf) + 1, 0);
if (ret <= 0 || 0 == strcmp("quit", buf))
{
printf("通信结束!\n");
delete cnw;
break;
}
ret = cnw->recv(buf, buf_size, 0);
if (ret <= 0)
{
delete cnw;
break;
}
printf("recv:%s bits:%d\n", buf, ret);
}
return 0;
}
下面我们先启动服务器再运行客户端进行测试,测试结果如下:
上图中,左边是服务器端,右边是客户端,可以看到,由客户端发送消息给服务端,服务端可以正常接收消息并响应客户端返回,客户端也可以接收服务器的响应,由此完成通信。
over
原文地址:https://blog.csdn.net/helloworld1932/article/details/143477229
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!