目录
引入
我们可以把之前写过的代码拿过来整合一下,直接封装出网络套接字的接口
- 这样之后再使用的话,直接调用接口即可
- 这里写的是tcp协议,也可以修改socket函数里的参数,改为udp协议
代码
cpp
#pragma once
#include <iostream>
#include <string>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
#include "Log.hpp"
enum
{
SOCK_ERROR = 2,
BIND_ERROR,
LISTEN_ERROR
};
int def_log = 10;
// 封装出socket接口
class MY_SOCKET
{
public:
MY_SOCKET()
: sockfd_(0)
{
}
~MY_SOCKET()
{
Close();
}
void Socket()
{
sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd_ < 0)
{
lg(FATAL, "socket create error, sockfd : %d,%s", sockfd_, strerror(errno));
exit(SOCK_ERROR);
}
lg(INFO, "socket create success, sockfd : %d", sockfd_);
}
void Bind(int port)
{
struct sockaddr_in *addr = new sockaddr_in;
memset(addr, 0, sizeof(*addr));
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = INADDR_ANY; // 接收任何主机发来的数据包
addr->sin_port = htons(port);
int t = bind(sockfd_, reinterpret_cast<struct sockaddr *>(addr), sizeof(*addr));
if (t < 0)
{
lg(FATAL, "bind error, sockfd : %d,%s", sockfd_, strerror(errno));
exit(BIND_ERROR);
}
lg(INFO, "bind success, sockfd : %d", sockfd_);
}
void Listen()
{
if (listen(sockfd_, def_log) < 0)
{
lg(FATAL, "listen error, sockfd : %d,%s", sockfd_, strerror(errno));
exit(LISTEN_ERROR);
}
lg(INFO, "listen success, sockfd : %d", sockfd_);
}
int Accept(std::string &clientip, uint16_t &clientport)
{
sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
memset(&client_addr, 0, client_len);
int sockfd = accept(sockfd_, reinterpret_cast<struct sockaddr *>(&client_addr), &client_len);
if (sockfd < 0)
{
lg(WARNING, "accept error, %s: %d", strerror(errno), errno);
return -1;
}
char client_ip[32];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, sizeof(client_ip));
clientip = client_ip;
clientport = ntohs(client_addr.sin_port);
return sockfd;
}
bool Connect(const std::string &ip, const uint16_t &port)
{
struct sockaddr_in *server_addr = new sockaddr_in;
memset(server_addr, 0, sizeof(*server_addr));
server_addr->sin_family = AF_INET;
inet_pton(AF_INET, ip.c_str(), &(server_addr->sin_addr));
server_addr->sin_port = htons(port);
int ret = connect(sockfd_, reinterpret_cast<struct sockaddr *>(server_addr), sizeof(*server_addr));
if (ret < 0)
{
printf("connect fail : %s:%d\n", ip.c_str(), port);
return false;
}
//printf("connect success\n");
return true;
}
void Close() // tcp协议在初始化好后,就不需要这个套接字了(子进程)
{
close(sockfd_);
}
int get_fd()
{
return sockfd_;
}
public:
int sockfd_;
};
log.hpp代码
里面用到的lg其实是我们自定义的日志对象
- 既可以在屏幕上打印,也可以将输出重定向到指定路径的文件里
代码如下:
cpp
#pragma once
#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define INFO 0
#define DEBUG 1
#define WARNING 2
#define ERROR 3
#define FATAL 4 // 致命的错误
#define SCREEN 1
#define ONEFILE 2
#define DEF_NAME "log.txt"
#define DEF_PATH "./log/"
#define SIZE 1024
class Log
{
public:
Log()
: method_(SCREEN), path_(DEF_PATH)
{
}
void enable()
{
method_ = ONEFILE;
}
void operator()(int level, const char *format, ...)
{
time_t t = time(nullptr);
struct tm *ctime = localtime(&t);
char leftbuffer[SIZE];
snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
ctime->tm_hour, ctime->tm_min, ctime->tm_sec);
va_list s;
va_start(s, format);
char rightbuffer[SIZE];
vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
va_end(s);
// 格式:默认部分+自定义部分
char logtxt[SIZE * 2];
snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);
printLog(logtxt);
}
~Log()
{
}
private:
std::string levelToString(int level)
{
switch (level)
{
case INFO:
return "INFO";
case DEBUG:
return "DEBUG";
case WARNING:
return "WARNING";
case ERROR:
return "ERROR";
case FATAL:
return "FATAL";
default:
return "NONE";
}
}
void printLog(const std::string &logtxt)
{
switch (method_)
{
case SCREEN:
std::cout << logtxt;
break;
case ONEFILE:
printOneFile(logtxt);
break;
default:
break;
}
}
void printOneFile(const std::string &info)
{
std::string path = path_ + DEF_NAME;
int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
if (fd > 0)
{
write(fd, info.c_str(), info.size());
close(fd);
}
else
{
return;
}
}
private:
int method_;
std::string path_;
};
Log lg;