struct sockaddr_in {
short sin_family; // 地址族,对于IPv4,它是 AF_INET
unsigned short sin_port; // 端口号(使用网络字节序)
struct in_addr sin_addr; // IPv4地址
char sin_zero[8]; // 填充0以使结构体与struct sockaddr的大小相同
};
command
是要执行的命令的字符串。type
是一个字符串,指定是读取命令的输出(使用 "r"
)还是向命令写入输入(使用 "w"
)。popen
返回一个 FILE *
指针,可以像处理任何其他文件流一样来处理它。如果 popen
调用失败,它将返回 NULL
#include "udpServer.hpp"
#include
using namespace std;
using namespace Server;
static void Usage(string proc)
{
cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
void handlerMessage(string clientip, uint16_t clientport, string message)
{
}
// ./udpServer port
int main(int argc, char *argv[])
{
if(argc != 2)
{
Usage(argv[0]);
exit(USAGE_ERR);
}
uint16_t port = atoi(argv[1]);
// string ip = argv[1];
std::unique_ptr usvr(new udpServer(handlerMessage, port));
usvr->initServer();
usvr->start();
return 0;
}
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static const std::string defalutIp="0.0.0.0";
static const int gnum=1024;
enum{
USAGE_ERR=1,
SOCKET_ERR,
BIND_ERR,
OPEN_ERR
};
typedef std::function func_t;
class udpServer{
public:
udpServer(const func_t &cb,uint16_t &port,const std::string ip=defalutIp):
_callback(cb),_port(port),_ip(ip),_sockfd(-1){}
void initServer(){
//1.创建socket
_sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(_sockfd==-1){
std::cerr<<"socket error"<0){
buffer[s]=0;
std::string clientip=inet_ntoa(peer.sin_addr);
uint16_t clientport=ntohs(peer.sin_port);
std::string message=buffer;
std::cout<
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
class udpClient{
public:
udpClient(const std::string&serverip,const uint16_t &serverport):
_serverip(serverip),_serverport(serverport),_sockfd(-1),_quit(false){}
void initClient(){
//创建socket
_sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(_sockfd==-1){
std::cerr<<"socket error:"<>message;
sendto(_sockfd,message.c_str(),message.size(),0,
(struct sockaddr*)&server,sizeof(server));
}
}
~udpClient(){
}
private:
int _sockfd;
std::string _serverip;
uint16_t _serverport;
bool _quit;
};
#include"udpServer.hpp"
#include
#include
#include
#include
using namespace std;
const string dicTxt="./dict.txt";
unordered_mapdict;
static void Usage(string proc){
cout<<"\nUsage:\n\t"<second;
//开始返回
struct sockaddr_in client;
bzero(&client,sizeof(client));
client.sin_family=AF_INET;
client.sin_port=htons(clientport);
client.sin_addr.s_addr=inet_addr(clientip.c_str());
sendto(sockfd,response_message.c_str(),response_message.size(),0,(struct sockaddr*)&client,
sizeof(client));
}
int main(int argc,char* argv[]){
if(argc!=2){
Usage(argv[0]);
exit(USAGE_ERR);
}
uint16_t port=atoi(argv[1]);
//string ip=argv[1];
unique_ptr usvr(new udpServer(handlerMessage,port));
usvr->initServer();
usvr->start();
return 0;
}
void execCommand(int sockfd, string clientip, uint16_t clientport, string cmd)
// {
//1. cmd解析,ls -a -l
// //2. 如果必要,可能需要fork, exec*
// if(cmd.find("rm") != string::npos || cmd.find("mv") != string::npos || cmd.find("rmdir") != string::npos)
// {
// cerr << clientip << ":" << clientport << " 正在做一个非法的操作: " << cmd << endl;
// return;
// }
// string response;
// FILE *fp = popen(cmd.c_str(), "r");
// if(fp == nullptr) response = cmd + " exec failed";
// char line[1024];
// while(fgets(line, sizeof(line), fp))
// {
// response += line;
// }
// pclose(fp);
// // 开始返回
// struct sockaddr_in client;
// bzero(&client, sizeof(client));
// client.sin_family = AF_INET;
// client.sin_port = htons(clientport);
// client.sin_addr.s_addr = inet_addr(clientip.c_str());
// sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));
// }
int listen(int sockfd, int backlog);
sockfd
: 这是之前已经创建并绑定到某个本地地址的 socket 的文件描述符。backlog
: 这个参数指定了允许排队等待接受的传入连接请求的最大数量。换句话说,它定义了连接请求的队列长度。sockfd
: 这是一个监听 socket 的文件描述符,之前已经通过 bind
和 listen
函数设置为监听模式。addr
: 这是一个指向 sockaddr
结构的指针,用于接收远程主机的地址信息(即客户端的地址信息)。addrlen
: 这是一个指向 socklen_t
变量的指针,该变量在调用时包含了 addr
所指向的地址结构的大小,调用返回时则包含了实际地址结构的大小。tcpClient.hpp
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#define NUM 1024
class TcpClient{
public:
TcpClient(const std::string &serverip,const uint16_t &serverport):
_sock(-1),_serverip(serverip),_serverport(serverport){}
void initClient(){
//1.创建socket
_sock=socket(AF_INET,SOCK_STREAM,0);
if(_sock<0){
std::cerr<<"sock create error"<0){
buffer[n]=0;
std::cout<<"Server回显#"<=0)
close(_sock);
}
private:
int _sock;
std::string _serverip;
uint16_t _serverport;
};
tcpClient.cc
#include"tcpClient.hpp"
#include
using namespace std;
static void Usage(string proc){
cout<<"\nUsage:\n\t"< tcli(new TcpClient(serverip,serverport));
tcli->initClient();
tcli->start();
return 0;
}
tcpServer.hpp
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"log.hpp"
enum{
USAGE_ERR=1,
SOCKET_ERR,
BIND_ERR,
LISTEN_ERR
};
static const uint16_t gport=8080;
static const int gbacklog=5;
class TcpServer{
public:
TcpServer(const uint16_t &port=gport):_listensock(-1),_port(gport){}
void initServer(){
//1.创建socket套接字
_listensock=socket(AF_INET,SOCK_STREAM,0);
if(_listensock<0){
logMessgae(FATAL,"create socket error");
exit(SOCKET_ERR);
}
logMessgae(NORMAL,"create socket sucess");
//2.bind绑定自己的网络信息
struct sockaddr_in local;
memset(&local,0,sizeof(local));
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=INADDR_ANY;
if(bind(_listensock,(struct sockaddr*)&local,sizeof(local))<0){
logMessgae(FATAL,"bind socket error");
exit(BIND_ERR);
}
logMessgae(NORMAL,"bind socket success");
//3.设置socket为监听状态
if(listen(_listensock,gbacklog)<0){
logMessgae(FATAL,"listen socket error");
exit(LISTEN_ERR);
}
logMessgae(NORMAL,"listen socket sucess");
}
void start(){
for(;;){
//4.server获取新链接
struct sockaddr_in peer;
socklen_t len=sizeof(peer);
int sock=accept(_listensock,(struct sockaddr*)&peer,&len);
if(sock<0){
logMessgae(ERROR,"accept error,next");
continue;
}
logMessgae(NORMAL,"accept a new link");
std::cout<<"sock:"<0){
buffer[n]=0;
std::cout<<"rev message"<
tcpServer.cc
#include"tcpServer.hpp"
#include
using namespace std;
static void Usage(string proc){
cout<<"\nUsage:\n\t"<tsvr(new TcpServer(port));
tsvr->initServer();
tsvr->start();
}
三次握手过程如下:
SYN(同步):在三次握手的第一步中,客户端发送一个SYN(同步)标志的数据包到服务器,以表示它想要建立连接。这个数据包包含一个客户端的初始序列号(ISN),这是用于TCP数据传输的一个关键参数。
SYN-ACK(同步-确认):服务器收到客户端的SYN包后,会发送一个SYN-ACK包作为回应。这个数据包包含服务器自己的初始序列号,以及对客户端初始序列号的确认(客户端的ISN+1)。
ACK(确认):在接收到服务器的SYN-ACK包后,客户端发送一个ACK包给服务器。这个ACK包包含对服务器初始序列号的确认(服务器的ISN+1)。
完成这三步之后,TCP连接就建立了,数据可以在客户端和服务器之间传输。这个过程的目的是同步双方的序列号和确认号,确保双方都准备好接收和发送数据,防止数据丢失或者重复。
四次挥手过程如下:
客户端发送FIN:当客户端完成数据传输并准备关闭连接时,它会发送一个FIN(结束)标志的数据包给服务器。这表示客户端没有更多的数据要发送,但它仍然可以接收数据。
服务器ACK客户端的FIN:服务器接收到客户端的FIN后,会回复一个ACK(确认)标志的数据包。这个ACK包是对客户端的FIN包的确认。此时,客户端到服务器的连接被关闭,但服务器到客户端的连接仍然开放,直到服务器准备好关闭连接。
服务器发送FIN:当服务器也完成了数据传输并准备关闭连接时,它会发送一个FIN标志的数据包给客户端。
客户端ACK服务器的FIN:客户端接收到服务器的FIN后,会回复一个ACK标志的数据包,确认收到了服务器的FIN包。在发送这个ACK包之后,客户端会进入一个名为TIME_WAIT的状态,持续等待足够的时间以确保服务器接收到了它的ACK包