C++模拟简单客户端服务端通信-Linux
程序员文章站
2022-06-06 08:30:17
...
客户端:
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
using namespace std;
//TCP client class
class C_TCP_Client
{
private:
int client_socket; //客户端套接字
public:
C_TCP_Client(); //默认构造函数
bool C_Connect(string, int); //建立连接函数
bool C_Recv(char *buf, int size); //接受数据函数
bool C_Send(char *buf, int size); //发送数据函数
~C_TCP_Client(); //析构函数
};
C_TCP_Client::C_TCP_Client()
{
client_socket = 0;
}
bool C_TCP_Client::C_Connect(string server_ip, int server_port)
{
//建立套接字
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if(client_socket == -1)
{
perror("socket");
return false;
}
//解析服务器域名
struct hostent* server_host = nullptr;
server_host = gethostbyname(server_ip.c_str());
if(server_host == nullptr)
{
cout << "gethostbyname failed\n";
return false;
}
//建立服务器信息结构体
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
memcpy(&server_addr.sin_addr, server_host->h_addr, server_host->h_length); //IP地址的赋值
//建立连接
if(connect(client_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)) != 0)
{
perror("connect");
return false;
}
return true;
}
bool C_TCP_Client::C_Recv(char * buf, int size)
{
int iret;
memset(buf, 0, size);
iret = recv(client_socket, buf, size, 0);
if(iret <= 0)
{
return false;
}
return true;
}
bool C_TCP_Client::C_Send(char *buf, int size)
{
int iret;
iret = send(client_socket, buf, size, 0);
if(iret <= 0)
{
return false;
}
return true;
}
C_TCP_Client::~C_TCP_Client()
{
close(client_socket);
}
int main()
{
string server_ip;
int server_port;
cout << "server_ip:";
cin >> server_ip;
cout << "server_port:";
cin >> server_port;
C_TCP_Client client_socket;
//建立连接
if(!client_socket.C_Connect(server_ip, server_port))
{
//失败返回
return -1;
}
//发送数据,客户端发送exit退出
char buf[1024];
while(1)
{
memset(buf, 0, sizeof(buf));
cin >> buf;
client_socket.C_Send(buf, strlen(buf));
if(memcmp(buf, "exit", 4) == 0)
{
break;
}
client_socket.C_Recv(buf, sizeof(buf));
cout << "接收:" << buf << endl;
}
return 0;
}
服务端:
#include <iostream>
#include <string.h>
#include <unistd.h> //进程
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
using namespace std;
class C_TCP_Server
{
private:
int listen_socket;
int client_socket;
public:
C_TCP_Server(); //默认构造函数
bool Listen(int); //监听函数
bool Accept(); //建立连接函数
bool Recv(char*, int); //接收数据函数
bool Send(char*, int); //发送数据函数
bool CloseClientSocket(); //关闭服务端中与客户端连接的套接字
bool CloseListenSocket(); //关闭服务端中用于监听的套接字
~C_TCP_Server(); //析构函数
};
C_TCP_Server::C_TCP_Server()
{
listen_socket = 0;
client_socket = 0;
}
bool C_TCP_Server::Listen(int port)
{
//监听套接字一旦监听后就一直运行着
//是否有连接请求是看accept函数是否接收到连接请求
//也就是说监听和连接应该设计成两个独立的函数
// 初始化监听套接字
if(listen_socket != 0)
{
close(listen_socket);
listen_socket = 0;
}
//建立监听套接字
listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if(listen_socket == -1)
{
perror("socket");
return false;
}
//初始化sockaddr结构体
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//将监听端口号与服务端信息结构体绑定
if(bind(listen_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0)
{
perror("bind");
close(listen_socket);
return false;
}
//开始监听
if(listen(listen_socket, 5) != 0)
{
perror("listen");
close(listen_socket);
return false;
}
return true;
}
bool C_TCP_Server::Accept()
{
//当受到连接请求时,建立连接
//建立客户端的结构体
/*这个结构体是保存连接上来的客户端的套接字信息,如果程序不需要这些信息,可以不设置*/
if((client_socket = accept(listen_socket, 0, 0)) <= 0)
{
perror("accept");
return false;
}
return true;
}
bool C_TCP_Server::Recv(char *buf, int size)
{
int iret;
memset(buf, 0, size);
if((iret = recv(client_socket, buf, size, 0)) <= 0)
{
return false;
}
return true;
}
bool C_TCP_Server::Send(char *buf, int size)
{
int iret;
if((iret = send(client_socket, buf, size, 0)) <= 0)
{
return false;
}
return true;
}
bool C_TCP_Server::CloseClientSocket()
{
close(client_socket);
client_socket = 0;
return true;
}
bool C_TCP_Server::CloseListenSocket()
{
close(listen_socket);
listen_socket = 0;
return true;
}
C_TCP_Server::~C_TCP_Server()
{
close(listen_socket);
close(client_socket);
}
int main()
{
signal(SIGCHLD, SIG_IGN); //忽略子进程退出的信号,避免产生僵尸进程
//开始监听
C_TCP_Server server_socket;
int port;
cout << "port:";
cin >> port;
//初始化并且开始监听
if(!server_socket.Listen(port))
{
//初始化或者监听过程中出现错误
return -1;
}
//开始检测连接
while(1)
{
if(server_socket.Accept() == false)
{
//没有接收到连接请求或者达到最大连接数量,继续循环
return 0;
}
//有连接,新建进程
int flg = fork();
if(flg > 0)
{
// fork返回值大于0是父进程,等于0是子进程,小于0是失败
// 父进程关闭client_socket,并继续等待接收连接
server_socket.CloseClientSocket();
continue;
}
//下面的代码只有子进程才能达到
//子进程只负责通信,不负责监听,所以关闭监听套接字,虽然这里还是使用server_socket,但是这个和if里面的server_socket是不一样的,因为开辟进程,所有信息都一样,所以变量名字也是重复的
server_socket.CloseListenSocket();
cout << "客户端已经连接" << endl;
//开始通信,接收数据,发送收到,如果接收的数据是exit,退出客户端
char buf[1024];
while(1)
{
memset(buf, 0, sizeof(buf));
server_socket.Recv(buf, sizeof(buf));
cout << "服务端接收到数据:" << buf << endl;
if(memcmp(buf, "exit", 4) == 0)
{
strcpy(buf, "服务端已经断开连接");
server_socket.Send(buf, strlen(buf));
break;
}
strcpy(buf, "服务端接收到你的数据");
server_socket.Send(buf, strlen(buf));
}
cout << "客户端已经断开连接" << endl;
return 0;
}
}
推荐阅读
-
nodejs socket服务端和客户端简单通信功能
-
linux网络编程之用socket实现简单客户端和服务端的通信(基于TCP)
-
MQTT(三)Python客户端+net客户端+net服务端 简单通信
-
socket通信 php作为客户端,C++作为服务端通信问题。
-
一个简单的服务端与客户端UDP通信
-
简单的服务端和客户端通信的一个程序
-
Day.55————C++ socket编程实现简单的UDP、TCP通信(服务端+客户端)
-
Socket TCP 协议实现服务端和客户端的简单通信
-
Linux/C++ I/O多路复用——poll模型实现服务端Socket通信
-
Linux(socket通信)--服务端与客户端编程