网络编程套接字——TCP
创始人
2024-03-28 19:24:06
0

一、单执行流(服务完了一个才能回应另一个客户端)

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)
}

相关内容

热门资讯

高新区一4S店发生燃爆致1死4... 12月28日,成都市公安局高新公安分局发布警情通报称,2025年12月28日下午,高新区南三环路四段...
吉利起诉欣旺达索赔23亿,最“... 文 | 超聚焦 辛辛苦苦干两年,结果到头还赔钱。 12月26日,欣旺达发布公告称,子公司欣旺达动力...
向上·2025湖湘经济关键词盘... 三湘都市报·新湖南客户端 全媒体记者 龙思言 “守住消费券发放时间,买了就是省钱!”近日,已有身孕的...
宁波这类车淘汰更新,补贴政策调... 此前 宁波市生态环境局等5部门联合印发了 《宁波市国四排放标准 非营运中、重型货车提前淘汰 及新能源...
成都警方通报:男子因纠纷引燃易... 12月28日,成都市公安局高新区分局发布警情通报: 12月28日下午,高新区南三环路四段一汽车销售服...
爱奇艺回应“男子充25年会员退... 近日,河南许昌黄先生充了25年爱奇艺会员后遭遇退费难一事受到关注,相关词条登上微博热搜。 据河南广播...
成都警方:一男子因纠纷引发燃爆... 12月28日,成都市公安局高新区分局发布警情通报: 12月28日下午,我区南三环路四段一汽车销售服务...
成都高新警方通报:男子因纠纷在... 本文转自【成都高新公安】; 12月28日,成都市公安局高新区分局发布警情通报:
青海一人在出租屋内遇害!犯罪嫌... 关于规范非机动车停放秩序的通告 2000年2月2日,同仁县(现同仁市)发生一起恶性刑事案件,受害人马...
成都警方:男子因纠纷于4S店外... 新京报讯 12月28日,成都警方发布警情通报,内容如下: 编辑 李忆林子