tcp_client.hpp
#pragma once#include
#include
#include
#include
#include
#include
#include
#includeclass TcpClient
{
private:std::string svr_ip;int svr_port;int sock;
public:TcpClient(std::string _ip,int _port):svr_ip(_ip),svr_port(_port),sozk(-1){}bool InitTcpClient()[sock = socket(AF_INET,SOCK_STREAM,0);if(sock < 0) //创建失败{std::cerr << "socket error" << std::endl;return false;}//不需要绑定,不需要监听return true;}//需要连接服务器void Start(){struct sockaddr_in peer;memset(&peer,0,sizeof(peer));peer.sin_family = AF_INET;peer.sin_port = htons(svr_port);peer.sin_addr.s_addr = inet_addr(svr_ip.c_str());if(connect(sock,(struct sockaddr*)&peer,sizeof(peer)) == 0){//successstd::cout << "connect success..." << std::endl;Request(sock);}else{//failstd::cout << "connect fail..." << std::endl;}}void Request(int sock){std::string message;char buffer[1024];while(true){std::cout << "Please Enter#";std::cin >> message; //输入消息write(sock,message.c_str(),message.size()); //发过去ssize_t s = read(sock,buffer,sizeof(buffer)-1); //读取发送过来的数据if(s > 0){buffer[s] = 0;std::cout << "server echo#" << buffer << std::endl;}}}~TcpClient(){if(sock >= 0)close(sock);}
};
tcp_client.cc
#include "tcp_client.hpp"void Usage(std::string proc)
{std::cout << "Usage: " << proc << "server_ip server_port" << std:;endl;
}
// 3个参数 :./client server_ip server_port
int main(int argc, char *argv[])
{if(argc != 3){Usage(argv[0]);return 1;}TcpClient tcli(argv[1],atoi(argv[2]));tcli.InitTcpClient();tcli.Start();return 0;
}
tcp_server.hpp
#pragma once
#include
#include
#include
#include
#include
#include
#include#define BACKLOG 5 //全连接队列长度
class TcpServer
{
private:int port;int listen_sock; //tcp是面向连接的,需要socket,监听套接字
public:TcpServer(int _port):port(_port),listen_sock(-1){}bool InitTcpServer(){listen_sock = socket(AF_INET,SOCK_STREAM,0);if(listen_sock < 0) //创建套接字失败 {std::cerr << "socket error" << std::endl;return false;}//绑定struct sockaddr_in local;memset(&local,0,sizeof(local)); //初始化local.sin_family = AE_INET;local.sin_port = hons(port);local.sin_addr.s_addr = INADDR_ANY;if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local)) < 0) //绑定失败{std::cerr << "bind error" << std::endl;return false;}//有连接到来,需要监听if(listen(listen_sock,BACKLOG) < 0) //监听失败{std::cerr << "listen error" << std::endl;return false;}return true;}void Loop(){ for(;;){//获取连接,知道连接的scoket与内容struct sockaddr_in peer;socklen_t len = sizeof(peer);int sock = accept(listen_sock,(struct sockaddr*)&peer,&len); //返回值是一个文件描述符 if(sock < 0){std::cerr << "accept error" << std:;endl;continue; //没有获取新连接成功,则继续获取}//inet_ntoa(peer.sin_addr):客户端IP地址(4字节IP转化成字符串点分十进制IP)//ntohs(peer.sin_port):客户端端口号,网络序列转为主机序列std::cout << "get a new link[" << inet_ntoa(peer.sin_addr) << "]" << ntohs(peer.sin_port) << std::endl; //处理请求std::string ip = inet_ntoa(peer.sin_addr);int port = ntohs(peer.sin_port);std::cout << "get a new link [" << ip << "]" << std::endl;Service(sock,ip,port);}}void Service(int sock,std::string ip,int port){char buffer[1024];while(true){ssize_t size = read(sock,buffer,sizeof(buffer)-1);if(size > 0){buffer[size] = 0;std::cout << ip <<":" << port <<"#" << buffer << std::endl;write(sock,buffer,size);}else if(size == 0){std::cout << ip <<":" << port <<"close" << std::endl;break;}else{std::cerr << sock << "read error" << std::endl;break;}}close(sock);std:;cout << "serice done" << std::endl;}~TcpServer(){if(listen_sock >= 0)close(listen_sock);}
};
tcp_server.cc
#include "tcp_server.hpp"
void Usage(std::string proc)
{std::cout << "Usage: " << proc << " port" << std::endl;
}
int main(int argc,char *argv[])
{if(argc != 2){Usage(argv[0]);return 1;}//TcpServer tsvr(8081);TcpServer tsvr(atoi(argv[1])); //argv[1]为程序名称tsvr.InitTcpServer();tsvr.Loop();
}
注意:
(1)accept函数 返回的是一个文件描述符,sock与listen_sock的联系,listen_sock相当于拉客的店小二,sock相当于进入饭店后为客人服务的服务员
listen_sock:获取新连接
sock:服务新连接(读取数据、分析数据、写入数据)
(2)ssize_t read(int fd,coid *buf,size_t count)
ssize > 0 :实际读取的字节
ssize_t == 0: 说明对端把链接关闭
ssize_t < 0:说明读取时遇到了错误
(3)
创建fork(),但是进程是阻塞的,解决方法如下:
法一:利用signal,
tcp_server.hpp
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include#define BACKLOG 5 //全连接队列长度
class TcpServer
{
private:int port;int listen_sock; //tcp是面向连接的,需要socket,监听套接字
public:TcpServer(int _port):port(_port),listen_sock(-1){}bool InitTcpServer(){listen_sock = socket(AF_INET,SOCK_STREAM,0);if(listen_sock < 0) //创建套接字失败 {std::cerr << "socket error" << std::endl;return false;}//绑定struct sockaddr_in local;memset(&local,0,sizeof(local)); //初始化local.sin_family = AE_INET;local.sin_port = hons(port);local.sin_addr.s_addr = INADDR_ANY;if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local)) < 0) //绑定失败{std::cerr << "bind error" << std::endl;return false;}//有连接到来,需要监听if(listen(listen_sock,BACKLOG) < 0) //监听失败{std::cerr << "listen error" << std::endl;return false;}return true;}void Loop(){ signal(SIGCHLD,SIG_IGN); //会自动释放退出进程//获取连接,知道连接的scoket与内容struct sockaddr_in peer;for( ; ; ){socklen_t len = sizeof(peer);int sock = accept(listen_sock,(struct sockaddr*)&peer,&len); //返回值是一个文件描述符 if(sock < 0){std::cerr << "accept error" << std:;endl;continue; //没有获取新连接成功,则继续获取}//inet_ntoa(peer.sin_addr):客户端IP地址(4字节IP转化成字符串点分十进制IP)//ntohs(peer.sin_port):客户端端口号,网络序列转为主机序列std::cout << "get a new link[" << inet_ntoa(peer.sin_addr) << "]" << ntohs(peer.sin_port) << std::endl; //处理请求std::string ip = inet_ntoa(peer.sin_addr);int port = ntohs(peer.sin_port);std::cout << "get a new link [" << ip << "]" << std::endl;pid_t id = fork(); //让子进程提供服务,子进程会继承父进程文件描述符if(id == 0){//child 管道Service(sock,ip,port);}//waitpid(); //阻塞的,非阻塞的话需要保存所有进程信息}}void Service(int sock,std::string ip,int port){char buffer[1024];while(true){ssize_t size = read(sock,buffer,sizeof(buffer)-1);if(size > 0){buffer[size] = 0;std::cout << ip <<":" << port <<"#" << buffer << std::endl;write(sock,buffer,size);}else if(size == 0){std::cout << ip <<":" << port <<"close" << std::endl;break;}else{std::cerr << sock << "read error" << std::endl;break;}}close(sock);std:;cout << "serice done" << std::endl;}~TcpServer(){if(listen_sock >= 0)close(listen_sock);}
};
法二:利用孤儿进程由OS回收
tcp_server.hpp
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include#define BACKLOG 5 //全连接队列长度
class TcpServer
{
private:int port;int listen_sock; //tcp是面向连接的,需要socket,监听套接字
public:TcpServer(int _port):port(_port),listen_sock(-1){}bool InitTcpServer(){listen_sock = socket(AF_INET,SOCK_STREAM,0);if(listen_sock < 0) //创建套接字失败 {std::cerr << "socket error" << std::endl;return false;}//绑定struct sockaddr_in local;memset(&local,0,sizeof(local)); //初始化local.sin_family = AE_INET;local.sin_port = hons(port);local.sin_addr.s_addr = INADDR_ANY;if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local)) < 0) //绑定失败{std::cerr << "bind error" << std::endl;return false;}//有连接到来,需要监听if(listen(listen_sock,BACKLOG) < 0) //监听失败{std::cerr << "listen error" << std::endl;return false;}return true;}void Loop(){ //第一种方法:signal(SIGCHLD,SIG_IGN); //会自动释放退出进程//获取连接,知道连接的scoket与内容struct sockaddr_in peer;for( ; ; ){socklen_t len = sizeof(peer);int sock = accept(listen_sock,(struct sockaddr*)&peer,&len); //返回值是一个文件描述符 if(sock < 0){std::cerr << "accept error" << std:;endl;continue; //没有获取新连接成功,则继续获取}//inet_ntoa(peer.sin_addr):客户端IP地址(4字节IP转化成字符串点分十进制IP)//ntohs(peer.sin_port):客户端端口号,网络序列转为主机序列std::cout << "get a new link[" << inet_ntoa(peer.sin_addr) << "]" << ntohs(peer.sin_port) << std::endl; //处理请求pid_t id = fork(); //爷爷 爸爸 孙子if(id == 0){//child 管道if(fork()> 0) {exit(0); //父进程直接终止,提供服务的是孙子进程,成为孤儿进程,直接由OS回收}std::string ip = inet_ntoa(peer.sin_addr);int port = ntohs(peer.sin_port);std::cout << "get a new link [" << ip << "]" << std::endl;Service(sock,ip,port); //孙子进程提供服务exit(0);}//waitpid(); //阻塞的//fatherclose(sock);waitpid(id,nullptr,0); //把爸爸回收}}void Service(int sock,std::string ip,int port){char buffer[1024];while(true){ssize_t size = read(sock,buffer,sizeof(buffer)-1);if(size > 0){buffer[size] = 0;std::cout << ip <<":" << port <<"#" << buffer << std::endl;write(sock,buffer,size);}else if(size == 0){std::cout << ip <<":" << port <<"close" << std::endl;break;}else{std::cerr << sock << "read error" << std::endl;break;}}close(sock);std:;cout << "serice done" << std::endl;}~TcpServer(){if(listen_sock >= 0)close(listen_sock);}
};
tcp_client.hpp
#pragma once#include
#include
#include
#include
#include
#include
#include
#includeclass TcpClient
{
private:std::string svr_ip;int svr_port;int sock;
public:TcpClient(std::string _ip,int _port):svr_ip(_ip),svr_port(_port),sozk(-1){}bool InitTcpClient()[sock = socket(AF_INET,SOCK_STREAM,0);if(sock < 0) //创建失败{std::cerr << "socket error" << std::endl;return false;}//不需要绑定,不需要监听return true;}//需要连接服务器void Start(){struct sockaddr_in peer;memset(&peer,0,sizeof(peer));peer.sin_family = AF_INET;peer.sin_port = htons(svr_port);peer.sin_addr.s_addr = inet_addr(svr_ip.c_str());if(connect(sock,(struct sockaddr*)&peer,sizeof(peer)) == 0){//successstd::cout << "connect success..." << std::endl;Request(sock);}else{//failstd::cout << "connect fail..." << std::endl;}}void Request(int sock){std::string message;char buffer[1024];while(true){std::cout << "Please Enter#";std::cin >> message; //输入消息write(sock,message.c_str(),message.size()); //发过去ssize_t s = read(sock,buffer,sizeof(buffer)-1); //读取发送过来的数据if(s > 0){buffer[s] = 0;std::cout << "server echo#" << buffer << std::endl;}}}~TcpClient(){if(sock >= 0)close(sock);}
};
tcp_client.cc
#include "tcp_client.hpp"void Usage(std::string proc)
{std::cout << "Usage: " << proc << "server_ip server_port" << std:;endl;
}
// 3个参数 :./client server_ip server_port
int main(int argc, char *argv[])
{if(argc != 3){Usage(argv[0]);return 1;}TcpClient tcli(argv[1],atoi(argv[2]));tcli.InitTcpClient();tcli.Start();return 0;
}
tcp_server.hpp
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include#define BACKLOG 5 //全连接队列长度
class TcpServer
{
private:int port;int listen_sock; //tcp是面向连接的,需要socket,监听套接字
public:TcpServer(int _port):port(_port),listen_sock(-1){}bool InitTcpServer(){listen_sock = socket(AF_INET,SOCK_STREAM,0);if(listen_sock < 0) //创建套接字失败 {std::cerr << "socket error" << std::endl;return false;}//绑定struct sockaddr_in local;memset(&local,0,sizeof(local)); //初始化local.sin_family = AE_INET;local.sin_port = hons(port);local.sin_addr.s_addr = INADDR_ANY;if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local)) < 0) //绑定失败{std::cerr << "bind error" << std::endl;return false;}//有连接到来,需要监听if(listen(listen_sock,BACKLOG) < 0) //监听失败{std::cerr << "listen error" << std::endl;return false;}return true;}void Loop(){ //第一种方法:signal(SIGCHLD,SIG_IGN); //会自动释放退出进程//获取连接,知道连接的scoket与内容struct sockaddr_in peer;for( ; ; ){socklen_t len = sizeof(peer);int sock = accept(listen_sock,(struct sockaddr*)&peer,&len); //返回值是一个文件描述符 if(sock < 0){std::cerr << "accept error" << std:;endl;continue; //没有获取新连接成功,则继续获取}//inet_ntoa(peer.sin_addr):客户端IP地址(4字节IP转化成字符串点分十进制IP)//ntohs(peer.sin_port):客户端端口号,网络序列转为主机序列std::cout << "get a new link[" << inet_ntoa(peer.sin_addr) << "]" << ntohs(peer.sin_port) << std::endl; //处理请求std::string ip = inet_ntoa(peer.sin_addr);int port = ntohs(peer.sin_port);std::cout << "get a new link [" << ip << "]" << std::endl;pid_t id = fork(); //爷爷 爸爸 孙子if(id == 0){//child 管道if(fork()> 0) {}Service(sock,ip,port);}//waitpid(); //阻塞的}}void Service(int sock,std::string ip,int port){char buffer[1024];while(true){ssize_t size = read(sock,buffer,sizeof(buffer)-1);if(size > 0){buffer[size] = 0;std::cout << ip <<":" << port <<"#" << buffer << std::endl;write(sock,buffer,size);}else if(size == 0){std::cout << ip <<":" << port <<"close" << std::endl;break;}else{std::cerr << sock << "read error" << std::endl;break;}}close(sock);std:;cout << "serice done" << std::endl;}~TcpServer(){if(listen_sock >= 0)close(listen_sock);}
};
tcp_server.cc
#include "tcp_server.hpp"
void Usage(std::string proc)
{std::cout << "Usage: " << proc << " port" << std::endl;
}
int main(int argc,char *argv[])
{if(argc != 2){Usage(argv[0]);return 1;}//TcpServer tsvr(8081);TcpServer tsvr(atoi(argv[1])); //argv[1]为程序名称tsvr.InitTcpServer();tsvr.Loop();
}
static void* HandlerRequest(void* arg)
{int sock = *(int*)arg;delete (int*)arg;pthread_detach(pthread_self());Service(int sock,std::string ip,int port)
}
下一篇:GC 算法总结_java培训