Network programming socket (c)
First, to achieve simple Tcp server (single-user)
- tcp_socket.hpp
#pragma once
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;
#define CHECK_RET(exp) if(!(exp)){\
return false;\
}
class TcpSocket
{
public:
TcpSocket()
:fd_(-1)
{}
TcpSocket(int fd)
:fd_(fd)
{}
bool Socket()
{
fd_ = socket(AF_INET,SOCK_STREAM,0);
if(fd_ < 0)
{
perror("socket is error");
return false;
}
printf("socket fd is successful! fd = %d\n",fd_);
return true;
}
bool Close()
{
printf("close fd! fd = %d ",fd_);
close(fd_);
return true;
}
bool Bind(const std::string& ip,uint16_t port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip.c_str());
addr.sin_port = htons(port);
int ret = bind(fd_,(sockaddr*)&addr,sizeof(addr));
if(ret < 0)
{
perror("bind is error");
return false;
}
return true;
}
bool Listen(int num = 5)
{
int ret = listen(fd_,num);
if(ret < 0)
{
perror("listen is error");
return false;
}
return true;
}
bool Accept(TcpSocket* peer,std::string* ip = nullptr,uint16_t* port = nullptr)
{
sockaddr_in peer_addr;
socklen_t len = sizeof(peer_addr);
int new_sock = accept(fd_,(sockaddr*)&peer_addr,&len);
if(new_sock < 0)
{
perror("accept is error");
return false;
}
printf("accept new fd! fd = %d\n",new_sock);
peer->fd_ = new_sock;
if(ip != nullptr)
{
*ip = inet_ntoa(peer_addr.sin_addr);
}
if(port != nullptr)
{
*port = ntohs(peer_addr.sin_port);
}
return true;
}
int Recv(std::string* buf)
{
buf->clear();
char temp[1024 * 10]= {0};
ssize_t read_size = recv(fd_,temp,sizeof(temp),0);
if(read_size < 0)
{
perror("recv is error");
return -1;
}
if(read_size == 0)
{
return 0;
}
buf->assign(temp,read_size);
return 1;
}
bool Send(const std::string& buf)
{
ssize_t write_size = send(fd_,buf.data(),buf.size(),0);
if(write_size < 0)
{
perror("send is error");
return false;
}
return true;
}
bool Connect(const std::string& ip,uint16_t port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip.c_str());
addr.sin_port = htons(port);
int ret = connect(fd_,(sockaddr*)&addr,sizeof(addr));
if(ret < 0)
{
perror("connect is error");
return false;
}
return true;
}
int GetFd()
{
return fd_;
}
private:
int fd_;
};
- tcp_server.hpp
#pragma once
#include <functional>
#include "tcp_socket.hpp"
typedef std::function<void (const std::string& req, std::string* resp)> Handler;
class TcpServer
{
public:
TcpServer(const std::string ip,uint16_t port)
:ip_(ip)
,port_(port)
{}
bool Start(Handler handler)
{
//1.创建socket
CHECK_RET(listen_sock_.Socket());
//2.绑定端口号
CHECK_RET(listen_sock_.Bind(ip_,port_));
//3.进行监听
CHECK_RET(listen_sock_.Listen());
//4.进入死循环处理事件
//
while(1)
{
//5.进行accept
TcpSocket new_sock;
std::string ip;
uint16_t port;
if(!listen_sock_.Accept(&new_sock,&ip,&port))
{
continue;
}
printf("[client %s : %d ]connect!",ip.c_str(),port);
//6.进行循环读取
while(1)
{
//7.读取请求
std::string req;
int ret = new_sock.Recv(&req);
if(ret < 0)
{
printf("[client %s : %d]disconnect!\n",ip.c_str(),port);
continue;
}
if(ret == 0)
{
printf("[client %s : %d]关闭了链接!\n",ip.c_str(),port);
new_sock.Close();
break;
}
printf("client say : [%s : %d]\n",ip.c_str(),port);
//8.计算响应
std::string resp;
handler(req,&resp);
//9.写回响应
new_sock.Send(resp);
printf("[%s:%d] req: %s, resp: %s\n", ip.c_str(), port,
req.c_str(), resp.c_str());
}
}
return true;
}
private:
TcpSocket listen_sock_;
std::string ip_;
uint16_t port_;
};
- tcp_client.hpp
#pragma once
#include "tcp_socket.hpp"
class TcpClient
{
public:
TcpClient(const std::string& ip, uint16_t port) : ip_(ip), port_(port)
{
// [注意!!] 需要先创建好 socket
sock_.Socket();
//
}
~TcpClient()
{
sock_.Close();
}
bool Connect()
{
return sock_.Connect(ip_, port_);
}
bool Recv(std::string* buf)
{
return sock_.Recv(buf);
}
bool Send(const std::string& buf)
{
return sock_.Send(buf);
}
private:
TcpSocket sock_;
std::string ip_;
uint16_t port_;
};
- dict_server.cc
#include <unordered_map>
#include "tcp_server.hpp"
std::unordered_map<std::string, std::string> g_dict;
void Translate(const std::string& req, std::string* resp)
{
auto it = g_dict.find(req);
if (it == g_dict.end())
{
*resp = "未找到";
return;
}
*resp = it->second;
return;
}
#if 0
int main(int argc, char* argv[])
{
if (argc != 3)
{
printf("Usage ./dict_server [ip] [port]\n");
return 1;
}
// 1. 初始化词典
g_dict.insert(std::make_pair("hello", "你好"));
g_dict.insert(std::make_pair("world", "世界"));
g_dict.insert(std::make_pair("bit", "贼NB"));
// 2. 启动服务器
TcpServer server(argv[1], atoi(argv[2]));
server.Start(Translate);
return 0;
//
}
#endif
int main()
{
// 1. 初始化词典
g_dict.insert(std::make_pair("hello", "你好"));
g_dict.insert(std::make_pair("world", "世界"));
g_dict.insert(std::make_pair("bit", "贼NB"));
// 2. 启动服务器
TcpServer server("0.0.0.0",9090);
server.Start(Translate);
return 0;
//
}
- dict_client.cc
#include "tcp_client.hpp"
#include <iostream>
int main(int argc, char* argv[])
{
if (argc != 3)
{
printf("Usage ./dict_client [ip] [port]\n");
return 1;
}
TcpClient client(argv[1], atoi(argv[2]));
bool ret = client.Connect();
if (!ret)
{
return 1;
}
for (;;)
{
std::cout << "请输入要查询的单词:" << std::endl;
std::string word;
std::cin >> word;
client.Send(word);
std::string result;
client.Recv(&result);
std::cout <<word<<" 意思是:"<< result << std::endl;
}
return 0;
}