C++网络编程学习笔记(三)——客户端编程代码
头文件"TcpConnect.h"
增加了Connect()函数封装
#pragma once
//因为操作繁琐,且和系统相关内容过多,对其进行封装
//初始化库,1.要么加一个函数初始化,要么在构造函数中做
#include<string>
class TcpConnect
{
public:
int sock = 0;
unsigned short port = 0;
std::string ip;
public:
TcpConnect();
virtual ~TcpConnect();
int CreatSocket();
bool Bind(unsigned short port);
//简化版本,如果想设置listen队列数量和IP地址可以重载,包含了bind和listen
TcpConnect Accept();
//注意返回的不是指针,是对象,所以不能在析构函数里释放,否则返回一次释放一次
//12min重听
//每进来一个连接,都返回该对象,判断client==0为失败
void Close();
//释放掉对象,否则socket会太多
int Recv(char* buf, int bufsize);
int Send(const char* buf, int sendsize);
//简单封装,只隐藏个别不用的参数,记得加const
bool Connect(const char*ip, unsigned short port);//暂时不考虑超时
//Connect 阻塞函数
};
cpp文件"TcpConnect.cpp"
增加了Connect()函数封装实现
//头文件必须放到cpp文件,不然调用者会产生影响,只对自己内部影响
#include "TcpConnect.h"
#ifdef _WIN32
#include<windows.h>
#else
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/unistd.h>
#endif
#include<iostream>
#include<thread>
using namespace std;
TcpConnect::TcpConnect()
{
#ifdef _WIN32
static bool first = true;
//保证只初始化一次,多次初始化也没啥影响,因为只是引用计数加1,但增加开销
if (first) {
first = false;
WSADATA ws;
WSAStartup(MAKEWORD(2, 2), &ws);
}
#endif
}
TcpConnect::~TcpConnect()
{
}
int TcpConnect::CreatSocket() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
cout << "creat error" << endl;
}
return sock;
}
bool TcpConnect::Bind(unsigned short port) {
if (sock <= 0)CreatSocket();//简化创建
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = htonl(0);
if (::bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0) {
cout << "bind failed";
return false;
}
listen(sock, 10);
return true;
}
TcpConnect TcpConnect::Accept() {
TcpConnect tcp;
sockaddr_in caddr;
int len = sizeof(caddr);
int client = accept(sock, (sockaddr*)&caddr, (int*)len);//阻塞函数,会一直等待连接
if (client <= 0)return tcp;
tcp.ip = inet_ntoa(caddr.sin_addr);//inet_ntoa多线程存在问题,实际中不用
tcp.port = ntohs(caddr.sin_port);
tcp.sock = client;
return tcp;
}
void TcpConnect::Close() {
if (sock <= 0)return;
closesocket(sock);
}
int TcpConnect::Recv(char* buf, int bufsize) {
return recv(sock, buf, bufsize, 0);//阻塞函数
}
int TcpConnect::Send(const char* buf, int sendsize) {
int sendedSize = 0;
while (sendedSize!= sendsize) {
int len = send(sock, buf + sendedSize, sendsize - sendedSize, 0);//阻塞函数
if (len <= 0)break;
sendedSize += len;
}
//循环发送,直到发送完成
return sendedSize;
}
bool TcpConnect::Connect(const char*ip, unsigned short port) {
if (sock <= 0)CreatSocket();
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = inet_addr(ip);
if (connect(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0) {
cout << "connect" << ip << ",port" << port << "error." << strerror(errno);
//后一个是打印错误信息
return false;
}
return true;
}
cpp文件"main.cpp"
#include<stdlib.h>//atoi函数
#include<thread>
#include<iostream>
#include"TcpConnect.h"
using namespace std;
int main(int argc, char **argv[]) {
TcpConnect client;
client.Connect("127.0.0.1", 8080);
//建立连接
client.Send("client", 6);
char buf[1024] = { 0 };
client.Recv(buf, sizeof(buf));
std::cout << buf;
return 0;
}