tcpsocket.hpp
#include<cstdio>
#include<iostream>
#include<string>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<cstring>
#define MAX_LISTEN 5
#define CHECK_RET(q) if((q)==false){return false;}
typedef struct
{
int num1;
int num2;
char op;
}tmp_t;
class TcpSocket
{
public:
TcpSocket():_sockfd(-1){}
bool Socket()
{
this->_sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(this->_sockfd <0)
{
perror("socket perror");
return false;
}
return true;
}
int GetFd()
{
return _sockfd;
}
void Addr(struct sockaddr_in* addr, const std::string& ip, uint16_t port)
{
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
addr->sin_addr.s_addr = inet_addr(ip.c_str());
return;
}
bool Bind(const std::string &ip, uint16_t port)
{
struct sockaddr_in addr;
Addr(&addr,ip,port);
socklen_t len = sizeof(struct sockaddr_in);
int ret = bind(_sockfd, (sockaddr*)&addr, len);
if(ret<0)
{
perror("bind error");
return false;
}
return true;
}
bool Listen(int backlog = MAX_LISTEN)
{
//int listen(描述符,同一时间最大连接数)
int ret =listen(_sockfd,backlog);
if(ret<0)
{
perror("listen error");
return false;
}
return true;
}
bool Connect(const std::string &ip, u_int16_t port)
{
//connect(描述符,服务端地址,服务端地址长度)
struct sockaddr_in addr;
Addr(&addr,ip,port);
socklen_t len = sizeof(struct sockaddr_in);
int ret = connect(_sockfd,(struct sockaddr*)&addr, len);
if(ret<0)
{
perror("connect error");
return false;
}
return true;
}
bool Accpet(TcpSocket* sock, std::string *ip=NULL, uint16_t *port = NULL)
{
//accept(监听描述符,客户端地址,地址长度)
struct sockaddr_in addr;
socklen_t len = sizeof(struct sockaddr_in);
int newfd = accept(_sockfd,(struct sockaddr*)&addr, &len);
if(newfd<0)
{
perror("accept error");
return false;
}
sock->_sockfd = newfd;
if(ip != NULL)
{
*ip = inet_ntoa(addr.sin_addr);
}
if(port != NULL)
{
*port = ntohs(addr.sin_port);
}
return true;
}
bool Send(const std::string &data)
{
//ssize_t send(描述符,数据,长度,标志)
int total =0;
while(total <(int)data.size())
{
int ret = send(_sockfd, &data[0]+total,data.size()-total,0);
if(ret <0)
{
printf("发送失败\n");
perror("send error");
return false;
}
total+=ret;
}
return true;
}
bool Recv(std::string *buf)
{
//ssize_t recv(描述符,缓冲区,长度,标志);
char tmp[4096]={0};
int ret = recv(_sockfd,tmp,4096,0);
if(ret<0)
{
perror("recv error");
return false;
}
if(ret ==0)
{
std::cout<<"peer shutdown"<<std::endl;
return false;
}
buf->assign(tmp,ret);//申请空间拷贝指定长度数据
return true;
}
bool Close()
{
if(_sockfd != -1)
{
close(_sockfd);
}
return true;
}
private:
int _sockfd;
};
tcp_srv.cpp(存在accept阻塞和recv阻塞,功能不完善)
#include"tcpsocket.hpp"
#include<string>
#include<cstring>
int main(int argc, char *argv[])
{
//argc是程序运行参数个数
//argv存放程序运行参数 ./tcp_srv 10.0.4.7 9000
if(argc !=3)
{
printf("useage: ./tcp_srv 10.0.4.7 9000");
return -1;
}
std::string ip = argv[1];
uint16_t port = std::stoi(argv[2]);
TcpSocket lst_sock;
//1.创建套接字
CHECK_RET(lst_sock.Socket());
//2.绑定地址信息
CHECK_RET(lst_sock.Bind(ip,port));
//3.开始监听
CHECK_RET(lst_sock.Listen());
while(1)
{
//4.获取新建连接
TcpSocket new_sock;
bool ret = lst_sock.Accpet(&new_sock,&ip,&port);
if(ret ==false)
{
usleep(1000);
continue;
}
std::cout<<"new conn- "<<ip<<":"<<port<<std::endl;
//5.通过新建链接与客户端通信
std::string buf;
ret = new_sock.Recv(&buf);
if(ret ==false)
{
new_sock.Close();
continue;
}
std::cout<<"client say: "<<buf<<std::endl;
buf.clear();
std::cout<<"server say: ";
std::cin>>buf;
ret = new_sock.Send(buf);
if(ret ==false)
{
new_sock.Close();
continue;
}
//6.关闭套接字
}
lst_sock.Close();
return 0;
}
process_tcp_srv.cpp(多进程版本)
#include"tcpsocket.hpp"
#include<string>
#include<cstring>
#include<signal.h>
void worker(TcpSocket &new_sock)
{
bool ret;
while(1)
{
//5.通过新建链接与客户端通信
std::string buf;
ret = new_sock.Recv(&buf);
if(ret ==false)
{
new_sock.Close();
return;
}
std::cout<<"client say: "<<buf<<std::endl;
buf.clear();
std::cout<<"server say: ";
std::cin>>buf;
ret = new_sock.Send(buf);
if(ret ==false)
{
new_sock.Close();
return;
}
}
}
int main(int argc, char *argv[])
{
//argc是程序运行参数个数
//argv存放程序运行参数 ./tcp_srv 10.0.4.7 9000
if(argc !=3)
{
printf("useage: ./tcp_srv 10.0.4.7 9000");
return -1;
}
signal(SIGCHLD, SIG_IGN);//避免产生僵尸进程
std::string ip = argv[1];
uint16_t port = std::stoi(argv[2]);
TcpSocket lst_sock;
//1.创建套接字
CHECK_RET(lst_sock.Socket());
//2.绑定地址信息
CHECK_RET(lst_sock.Bind(ip,port));
//3.开始监听
CHECK_RET(lst_sock.Listen());
while(1)
{
//4.获取新建连接
TcpSocket new_sock;
bool ret = lst_sock.Accpet(&new_sock,&ip,&port);
if(ret ==false)
{
usleep(1000);
continue;
}
std::cout<<"new conn- "<<ip<<":"<<port<<std::endl;
//创建一个新的子进程与客户端进行通信
pid_t pid = fork();
if(pid ==0)
{
worker(new_sock);
new_sock.Close();
exit(0);
}
//反而如果不关闭,会造成资源泄露
new_sock.Close();//这个关闭不会影响客户端-父子进程数据独有
}
//6.关闭套接字
lst_sock.Close();
return 0;
}
pthread_tcp_srv.cpp(多线程版本)
#include"tcpsocket.hpp"
#include<string>
#include<cstring>
#include<pthread.h>
void* worker(void* arg)
{
TcpSocket* new_sock = (TcpSocket*)arg;
while(1)
{
int ret =0;
//5.通过新建链接与客户端通信
std::string buf;
ret = new_sock->Recv(&buf);
if(ret ==false)
{
new_sock->Close();
continue;
}
std::cout<<"client say: "<<buf<<std::endl;
buf.clear();
std::cout<<"server say: ";
std::cin>>buf;
ret = new_sock->Send(buf);
if(ret ==false)
{
new_sock->Close();
delete new_sock;
return NULL;
}
}
return NULL;
}
int main(int argc, char *argv[])
{
//argc是程序运行参数个数
//argv存放程序运行参数 ./tcp_srv 10.0.4.7 9000
if(argc !=3)
{
printf("useage: ./tcp_srv 10.0.4.7 9000");
return -1;
}
std::string ip = argv[1];
uint16_t port = std::stoi(argv[2]);
TcpSocket lst_sock;
//1.创建套接字
CHECK_RET(lst_sock.Socket());
//2.绑定地址信息
CHECK_RET(lst_sock.Bind(ip,port));
//3.开始监听
CHECK_RET(lst_sock.Listen());
while(1)
{
//4.获取新建连接
TcpSocket* new_sock=new TcpSocket();
bool ret = lst_sock.Accpet(new_sock,&ip,&port);
if(ret ==false)
{
usleep(1000);
continue;
}
std::cout<<"new conn- "<<ip<<":"<<port<<std::endl;
pthread_t tid;
pthread_create(&tid,NULL,worker,(void*)new_sock);
pthread_detach(tid);
//new通_sock.Close();//线程之间共享文件描述符表
//6.关闭套接字
}
lst_sock.Close();
return 0;
}
tcp_cli.cpp
#include"tcpsocket.hpp"
#include<string>
int main(int argc, char* argv[])
{
if(argc !=3)
{
printf("useage: ./tcp_cli srvip srvport\n");
return -1;
}
std::string srv_ip = argv[1];
int16_t srv_port = std::stoi(argv[2]);
TcpSocket cli_sock;
//1.创建套接字
CHECK_RET(cli_sock.Socket());
//2.绑定地址信息
//3.向服务端发起连接请求
CHECK_RET(cli_sock.Connect(srv_ip,srv_port));
while(1)
{
//4.与服务端进行通信
std::string buf;
std::cout<<"client say:";
std::cin>>buf;
CHECK_RET(cli_sock.Send(buf));
buf.clear();
CHECK_RET(cli_sock.Recv(&buf));
std::cout<<"server say: "<<buf<<std::endl;
}
//5.关闭套接字
cli_sock.Close();
return 0;
}