0
点赞
收藏
分享

微信扫一扫

多进程socket通信

Separes 2022-03-26 阅读 47
c++

 服务端

#include<stdio.h>
#include <string.h>
#include <unistd.h>  //系统调用的接口
#include <netdb.h>  //网络有关
#include <sys/types.h> //linux相关基本数据类型
#include <sys/socket.h>
#include <arpa/inet.h>

class CTcpServer{
public:
    int m_listenfd; //监听socket
    int m_clientfd; // 监听之后接受连接的socket
    
    CTcpServer(){
        m_listenfd = 0; //初始化为0
    }

    ~CTcpServer(){
        close(m_listenfd);
        close(m_clientfd);
    }

    bool  InitServer(int port){
        m_listenfd = socket(AF_INET, SOCK_STREAM, 0);//第三个表示协议,0表示默认tcp协议
        struct sockaddr_in Serveraddr;
        //先初始化再赋值
        memset(&Serveraddr, 0, sizeof(Serveraddr));
        Serveraddr.sin_family = AF_INET;
        Serveraddr.sin_addr.s_addr = htons(INADDR_ANY);
        Serveraddr.sin_port = htons(port);
        if(bind(m_listenfd, (struct sockaddr *)&Serveraddr, sizeof(Serveraddr) ) != 0){
            printf("绑定失败\n");
            close(m_listenfd);
            return false;
        }
        if(listen(m_listenfd, 5) !=0){
            printf("监听失败\n");
            close(m_listenfd);
            return false;
        }

        return true;

    }

    bool Accept(){
        struct sockaddr_in clientaddr;
        
        //if((m_clientfd = accept(m_listenfd, (struct sockaddr *)&clientaddr, sizeof(clientaddr))) <= 0) 
        if((m_clientfd = accept(m_listenfd, 0, 0)) <= 0) //为什么是0,0
            return false;
        return true;
    }


    void CloseClient(){
        close(m_clientfd);
        return ;
    }
    void CloseListen(){
        close(m_listenfd);
        return ;
    }
    
};


CTcpServer TcpServer;
int main(){
    if(TcpServer.InitServer(5001) == false){
        printf("服务端初始化失败\n");
        return -1;
    }
    while(1){
        if(TcpServer.Accept() == false) continue;

        int pid = fork();
        if(pid != 0){
            TcpServer.CloseClient();
            continue;

        }
        else{
            TcpServer.CloseListen();
            printf("客户端已连接\n");
            char buffer[1024];
            while(1){
                memset(buffer, 0, sizeof(buffer));//表示动态分配内存的大小, 比如指针指向的数组是4
                if(recv(TcpServer.m_clientfd ,buffer, sizeof(buffer), 0 ) <= 0) break;//实际的长度
                printf("接收:%s\n", buffer);
                strcpy(buffer, "OK");
                if(send(TcpServer.m_clientfd ,buffer, strlen(buffer), 0) <= 0) break;
                printf("发送:%s\n", buffer);
            }
        }
        printf("客户端已经断开\n");
        return 0;

    }

}

客户端

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
 
// TCP客户端类
class CTcpClient
{
public:
  int m_sockfd;
 
  CTcpClient();
 
  // 向服务器发起连接,serverip-服务端ip,port通信端口
  bool ConnectToServer(const char *serverip,const int port);
  // 向对端发送报文
  int  Send(const void *buf,const int buflen);
  // 接收对端的报文
  int  Recv(void *buf,const int buflen);
 
 ~CTcpClient();
};
 
int main()
{
  CTcpClient TcpClient;
 
  // 向服务器发起连接请求
  if (TcpClient.ConnectToServer("192.168.23.128",5001)==false)
  { printf("TcpClient.ConnectToServer(\"172.16.0.15\",5051) failed,exit...\n"); return -1; }
 
  char strbuffer[1024];
 
  for (int ii=0;ii<5;ii++)
  {
    memset(strbuffer,0,sizeof(strbuffer));
    sprintf(strbuffer,"这是第%d个超级女生,编号%03d。",ii+1,ii+1);
    if (TcpClient.Send(strbuffer,strlen(strbuffer))<=0) break;
    printf("发送:%s\n",strbuffer);
   
    memset(strbuffer,0,sizeof(strbuffer));
    if (TcpClient.Recv(strbuffer,sizeof(strbuffer))<=0) break;
    printf("接收:%s\n",strbuffer);
 
    sleep(1);  // sleep一秒,方便观察程序的运行。
  }
}
 
CTcpClient::CTcpClient()
{
  m_sockfd=0;  // 构造函数初始化m_sockfd
}
 
CTcpClient::~CTcpClient()
{
  if (m_sockfd!=0) close(m_sockfd);  // 析构函数关闭m_sockfd
}
 
// 向服务器发起连接,serverip-服务端ip,port通信端口
bool CTcpClient::ConnectToServer(const char *serverip,const int port)
{
  m_sockfd = socket(AF_INET,SOCK_STREAM,0); // 创建客户端的socket
 
  struct hostent* h; // ip地址信息的数据结构  转化成网络字节序
  if ( (h=gethostbyname(serverip))==0 )
  { close(m_sockfd); m_sockfd=0; return false; }
 
  // 把服务器的地址和端口转换为数据结构
  struct sockaddr_in servaddr;
  memset(&servaddr,0,sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(port);
  memcpy(&servaddr.sin_addr,h->h_addr,h->h_length);
 
  // 向服务器发起连接请求
  if (connect(m_sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))!=0)
  { close(m_sockfd); m_sockfd=0; return false; }
 
  return true;
}
 
int CTcpClient::Send(const void *buf,const int buflen)
{
  return send(m_sockfd,buf,buflen,0);
}
 
int CTcpClient::Recv(void *buf,const int buflen)
{
  return recv(m_sockfd,buf,buflen,0);
}

多进程和单进程的区别在于服务端的处理,多进程可以同时接受很多个客户端的连接并通信。

 这里使用类来封装socket,他的作用是

1)把数据初始化的代码放在构造函数中;

2)把关闭socket等释放资源的代码放在析构函数中;

3)把socket定义为类的成员变量,类外部的代码根本看不到socket。

4)代码更简洁,更安全(析构函数自动调用关闭socket,释放资源)。

举报

相关推荐

0 条评论