当前位置: 首页 > news >正文

Linux网络Socket编程TCP

相关接口

创建socket和udp的差不多,只不过type设为SOCK_STREAM,绑定方式一样,相比udp,要设置监听的状态,还要建立连接。

监听:

接收连接

成功了,返回一个文件描述符,将来通信就用这个fd,而之前创建socket的fd是用来获取新连接的。

建立连接

成功0,失败-1。

使用案例

回显服务器

//Log.hpp
#pragma once
#include<unistd.h>
#include<iostream>
#include<time.h>
#include<stdarg.h>
#include<fstream>
#include<string.h>
#include<pthread.h>
enum
{DEBUG = 1,INFO,WARNING,ERROR,FATAL
};
const std::string logfile = "log.txt";
pthread_mutex_t _mutex;
#define SCREEN_TYPE 1
#define FILE_TYPE 2
std::string LevelToString(int level)
{switch (level){case DEBUG:return "DEBUG";break;case INFO:return "INFO";break;case ERROR:return "ERROR";break;case WARNING:return "WARNING";break;case FATAL:return "FATAL";break;default:return "UNKONW";break;}
}
std::string GetTime()
{time_t now = time(nullptr);struct tm *curr = localtime(&now);char buf[128];snprintf(buf, sizeof(buf), "%d-%02d-%02d %02d:%02d:%02d",curr->tm_year+1900,curr->tm_mon+1,curr->tm_mday,curr->tm_hour,curr->tm_min,curr->tm_sec);return buf;
}
class LockGuard
{
public:LockGuard(pthread_mutex_t* td):_td(td){pthread_mutex_lock(_td);}~LockGuard(){pthread_mutex_unlock(_td);}private:pthread_mutex_t *_td;
};
class Logmessage
{
public:std::string _level;pid_t _id;std::string _filename;int _filenumber;//行号std::string _curr_time;std::string _message_info;
};
class Log
{
public:Log(const std::string& filename=logfile):_logfile(filename){}void Enable(int type){_type = type;}void FlushToScreen(Logmessage& lg){printf("[%s][%d][%s][%d][%s] %s", lg._level.c_str(), lg._id, lg._filename.c_str(), lg._filenumber, lg._curr_time.c_str(), lg._message_info.c_str());}void FlushToFile(Logmessage& lg){std::ofstream t(_logfile,std::ios::app);if(!t.is_open())return;char logtxt[1024];snprintf(logtxt,sizeof(logtxt),"[%s][%d][%s][%d][%s] %s", lg._level.c_str(), lg._id, lg._filename.c_str(), lg._filenumber, lg._curr_time.c_str(), lg._message_info.c_str());t.write(logtxt, strlen(logtxt));t.close();}void FlushLog(Logmessage& lg){LockGuard ld(&_mutex);// 此处可以加过滤,本代码没加if(_type==SCREEN_TYPE){FlushToScreen(lg);}else if(_type==FILE_TYPE){FlushToFile(lg);}}void logmessage(int level,std::string filename,int filenumber,const char* format,...){Logmessage lg;lg._level = LevelToString(level);lg._id = getpid();lg._filename = filename;lg._filenumber = filenumber;lg._curr_time = GetTime();va_list ap;va_start(ap, format);char info[512];vsnprintf(info, sizeof(info), format, ap);va_end(ap);lg._message_info = info;FlushLog(lg);}~Log(){}
private:int _type=SCREEN_TYPE;std::string _logfile;
};
Log lg;
#define LOG(level,format,...) do{lg.logmessage(level, __FILE__, __LINE__, format, ##__VA_ARGS__);}while (0)
#define EnableScreen() do{ lg.Enable(SCREEN_TYPE);} while (0)
#define EnableFILE() do{ lg.Enable(FILE_TYPE);} while (0)
//InetAddr.hpp
#pragma once
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<iostream>
using namespace std;
class InetAddr
{
private:void ToHost(){_port = ntohs(_addr.sin_port);_ip = inet_ntoa(_addr.sin_addr);}
public:InetAddr(const struct sockaddr_in& addr):_addr(addr){ToHost();}string Ip() { return _ip; }uint16_t Port() { return _port; }private:string _ip;uint16_t _port;struct sockaddr_in _addr;
};
//TcpServer.hpp
#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include"Log.hpp"
#include<cstring>
#include"InetAddr.hpp"
#include<sys/wait.h>
using namespace std;
const static uint16_t gport = 6666;
const static int gsock = -1;
const static int gblcklog = 8;
enum
{SOCKET_ERROR = 1,BIND_ERROR,LISTEN_ERROR
};class TcpServer
{
public:TcpServer(uint16_t port=gport):_port(port),_listensockfd(gsock){}class ThreadDate{public:ThreadDate(int sockfd,TcpServer* self,const InetAddr& addr):_sockfd(sockfd),_self(self),_addr(addr){}int _sockfd;TcpServer *_self;InetAddr _addr;};void InitServer(){_listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);if(_listensockfd<0){LOG(FATAL, "socket create error\n");exit(SOCKET_ERROR);}LOG(INFO, "socket create success\n");struct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;int n = ::bind(_listensockfd, (sockaddr *)&local, sizeof(local));if(n<0){LOG(FATAL, "bind error\n");exit(BIND_ERROR);}LOG(INFO, "bind success\n");//tcp面向连接,要求不断获取连接,因此设为listen状态if(::listen(_listensockfd,gblcklog)<0){LOG(FATAL, "listen error\n");exit(LISTEN_ERROR);}LOG(INFO, "listen success\n");}void Loop(){_isrunning = true;while(_isrunning){struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = ::accept(_listensockfd, (struct sockaddr *)&client, &len);if(sockfd<0){LOG(WARNING, "accept error\n");continue;}InetAddr addr(client);LOG(INFO, "new connect %s\n",addr.Ip().c_str());// //多进行版本// pid_t id=fork();// if(id==0)// {//     ::close(_listensockfd);//     //让孙子变成孤儿,然后执行任务//     if(fork()>0)//         exit(0);//     Service(sockfd,addr);//     exit(0);// }// ::close(sockfd);// int n = waitpid(id, nullptr, 0);// if(n>0)// {//     LOG(INFO, "wait child success\n");// }//多线程版本pthread_t tid;ThreadDate *td = new ThreadDate(sockfd, this,addr);pthread_create(&tid, nullptr, Excute, td);}}static void* Excute(void* args){pthread_detach(pthread_self());ThreadDate *td = static_cast<ThreadDate *>(args);td->_self->Service(td->_sockfd,td->_addr);delete td;return nullptr;}void Service(int sockfd,InetAddr addr){while(1){char buf[512];ssize_t n = ::read(sockfd, buf, sizeof(buf) - 1);if(n>0){buf[n] = 0;string msg = "[" + addr.Ip() + "]:" + buf;::write(sockfd, msg.c_str(), msg.size());}else if(n==0){LOG(INFO, "client %s quit\n", addr.Ip().c_str());break;}else{LOG(ERROR, "read %s error\n", addr.Ip().c_str());break;}}::close(sockfd);}~TcpServer(){}private:uint16_t _port;int _listensockfd;bool _isrunning=false;};
//TcpServerMain.cpp
#include"TcpServer.hpp"
#include<memory>
int main()
{std::unique_ptr<TcpServer> server = std::make_unique<TcpServer>();server->InitServer();server->Loop();return 0;
}
//TcpClientMain.cpp
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<cstring>
#include"InetAddr.hpp"
using namespace std;
int main(int argc, char *argv[])
{if (argc != 3){cerr << "usage:" << argv[0] << "error" << endl;exit(0);}string serverip = argv[1];uint16_t serverport = htons(stoi(argv[2]));//创建int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);if(sockfd<0){cout<<"create socket error"<<endl;exit(1);}//不需要显示绑定,会自己随机生产端口//建立连接struct sockaddr_in server;server.sin_port = serverport;server.sin_family = AF_INET;::inet_pton(AF_INET, serverip.c_str(), &server.sin_addr);int n = ::connect(sockfd, (struct sockaddr *)&server, sizeof(server));if(n<0){cerr << "connect error" << endl;exit(1);}while(1){string message;cout << "Enter:";getline(std::cin, message);write(sockfd, message.c_str(), message.size());char buf[512];int n=read(sockfd, buf, sizeof(buf) - 1);if(n>0){buf[n] = 0;cout << "server:" << buf << endl;}else {break;}}::close(sockfd);return 0;
}

多线程远程命令执行

创建管道,创建子进程然后子进程去执行command,把结果写到管道。

在上面的基础上把服务器改一改.

#pragma once
#include "Log.hpp"
#include "InetAddr.hpp"
#include <string>
#include<cstdio>
class Command
{
public:Command() {}string Excute(const string& cmdstr){string result;FILE *fp = popen(cmdstr.c_str(), "r");if(fp){char line[512];while(fgets(line,sizeof(line),fp)){result += line;}return result.empty()?"success":result;}else{return "execute error";}}void HanderCommand(int sockfd, InetAddr addr){while (1){char buf[512];ssize_t n = ::recv(sockfd, buf, sizeof(buf) - 1,0);if (n > 0){buf[n] = 0;string msg = "[" + addr.Ip() + "]:" + buf;LOG(INFO, "%s\n", msg.c_str());string result=Excute(buf);::send(sockfd, result.c_str(), result.size(), 0);}else if (n == 0){LOG(INFO, "client %s quit\n", addr.Ip().c_str());break;}else{LOG(ERROR, "read %s error\n", addr.Ip().c_str());break;}}::close(sockfd);}~Command() {}
};
//TcpServer.hpp
#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include"Log.hpp"
#include<cstring>
#include"InetAddr.hpp"
#include<sys/wait.h>
#include<functional>
using namespace std;
using command_service_t = function<void(int, InetAddr)>;
const static uint16_t gport = 6666;
const static int gsock = -1;
const static int gblcklog = 8;
enum
{SOCKET_ERROR = 1,BIND_ERROR,LISTEN_ERROR
};class TcpServer
{
public:TcpServer(command_service_t service,uint16_t port=gport):_port(port),_listensockfd(gsock),_service(service){}class ThreadDate{public:ThreadDate(int sockfd,TcpServer* self,const InetAddr& addr):_sockfd(sockfd),_self(self),_addr(addr){}int _sockfd;TcpServer *_self;InetAddr _addr;};void InitServer(){_listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);if(_listensockfd<0){LOG(FATAL, "socket create error\n");exit(SOCKET_ERROR);}LOG(INFO, "socket create success\n");struct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;int n = ::bind(_listensockfd, (sockaddr *)&local, sizeof(local));if(n<0){LOG(FATAL, "bind error\n");exit(BIND_ERROR);}LOG(INFO, "bind success\n");//tcp面向连接,要求不断获取连接,因此设为listen状态if(::listen(_listensockfd,gblcklog)<0){LOG(FATAL, "listen error\n");exit(LISTEN_ERROR);}LOG(INFO, "listen success\n");}void Loop(){_isrunning = true;while(_isrunning){struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = ::accept(_listensockfd, (struct sockaddr *)&client, &len);if(sockfd<0){LOG(WARNING, "accept error\n");continue;}InetAddr addr(client);LOG(INFO, "new connect %s\n",addr.Ip().c_str());// //多进行版本// pid_t id=fork();// if(id==0)// {//     ::close(_listensockfd);//     //让孙子变成孤儿,然后执行任务//     if(fork()>0)//         exit(0);//     Service(sockfd,addr);//     exit(0);// }// ::close(sockfd);// int n = waitpid(id, nullptr, 0);// if(n>0)// {//     LOG(INFO, "wait child success\n");// }//多线程版本pthread_t tid;ThreadDate *td = new ThreadDate(sockfd, this,addr);pthread_create(&tid, nullptr, Excute, td);}}static void* Excute(void* args){pthread_detach(pthread_self());ThreadDate *td = static_cast<ThreadDate *>(args);td->_self->_service(td->_sockfd,td->_addr);delete td;return nullptr;}~TcpServer(){}private:uint16_t _port;int _listensockfd;bool _isrunning=false;command_service_t _service;
};
//TcpServer.cpp
#include"TcpServer.hpp"
#include"Command.hpp"
#include<memory>
int main()
{Command cmdservice;command_service_t func = std::bind(&Command::HanderCommand,&cmdservice, std::placeholders::_1, std::placeholders::_2);std::unique_ptr<TcpServer> server = std::make_unique<TcpServer>(func);server->InitServer();server->Loop();return 0;
}

http://www.dtcms.com/a/438615.html

相关文章:

  • 神卓云监控 K900 在海康 / 大华异地监控场景中的应用实践
  • 深圳专业网站开发上海公司建立网站吗
  • Photoshop - Photoshop 工具栏(1)移动工具
  • 怎么给网站做域名重定向公司网站建设合规吗
  • [创业之路-664]:越是通用的东西,适用的范围越广,解决问题的受众越多,解决方案的提供商越垄断,强者恒强。因此,通用 人工智能的服务是少数大厂的游戏。
  • id创建网站桐乡市城乡规划建设局网站
  • 网站建设谈单情景对话html响应式网页设计代码范文
  • 设计图片免费素材网站做网站运营需要什么资源
  • gas 优化
  • [创业之路-667]:第四次工业革命(智能革命)未来将创造大量的财富,普通人通过哪些方式参与这些财富的创造与分享?
  • New StarsAI1.0.1
  • 青岛高端网站制作培训机构网站建设要求
  • Spring AI 实战:构建智能对话系统
  • Font Awesome 医疗图标
  • 同时显示文件夹大小的其它“免费”方案
  • Vue--Vue基础(二)
  • 高端网站建设搭建服装定制尺寸量身表
  • linux banner 设计
  • WordPress之家
  • php企业网站开发好学么承德网
  • 从技术史看:Unix 从何而来
  • qt 可以做网站吗优化师简历
  • DreamControl——结合扩散模型和RL的全身人形控制:利用在人体运动数据上训练得到的扩散先验,随后在仿真中引导RL策略完成特定任务
  • Spring Boot 实现邮件发送功能:整合 JavaMailSender 与 FreeMarker 模板
  • 新手理解的电子IO口
  • 网站开发完整项目案例做视频网站视频短片
  • 怎样自己做一个网站想创建一个网站
  • wordpress本站只对会员开放网站建设求职要求
  • PyQt5 QLineEdit案例大全:进阶实战应用指南
  • 技术博客SEO优化指南