linux下tcp服务端与客户端实现

背景

使用socket完成linux下服务端与客户端的编写,传输层使用tcp协议,服务端使用多进程实现并发。

代码

服务端

Server.h

#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <net/if.h>
enum ServerType{
    TCP,
    UDP,
};

class Server{
public:
    Server();
    ~Server();
    bool start(int domain, ServerType serverType, short int port);
    bool stop();
private:
    int listenfd;
    sockaddr_in addr;
};

Server.cpp

#include "Server.h"
Server::Server(){
    listenfd = -1;
}
Server::~Server()
{
}
bool Server::start(int domain, ServerType serverType, short int port)
{
    addr.sin_family = domain;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(port);
    if(serverType == ServerType::TCP){
        listenfd = socket(domain, SOCK_STREAM, 0);
    }
    else{
        listenfd = socket(domain, SOCK_DGRAM, 0);
    }
    
    if(listenfd < 0){
        printf("create socket error\n");
        return false;
    }
    
    if(bind(listenfd, (sockaddr *)&addr, sizeof(addr)) < 0){
        printf("bind error: %d, %s\n", listenfd, strerror(errno));
        return false;
    }
    if(listen(listenfd, 5) < 0){
        printf("listen error\n");
        return false;
    }
    printf("successfully create server\n");
    
    while(1){
        sockaddr_in client_addr;
        socklen_t len = sizeof(client_addr);
        int client_fd = accept(listenfd, (sockaddr *)&client_addr, &len);
        if(client_fd < 0){
            printf("invalid client fd: %d, %s\n", client_fd, strerror(errno));
            continue;
        }
        pid_t t= fork();
        printf("fork\n");
        if(t > 0){ // 主进程
            close(client_fd);
            continue;
        }
        else if(t == 0){    // 子进程
            close(listenfd);
            char buf[1024] = {0};
            if(recv(client_fd, buf, sizeof(buf), 0) > 0){
                printf("recv message: %s from client!\n", buf);
            }
            close(client_fd);
            exit(0);
        }
    }
    return true;
}

bool Server::stop()
{
    if(listenfd > 0){
        close(listenfd);
    }
    return true;
}

tcpServer.cpp

#include "Server.h"

int main(){
    Server tcpServer;
    tcpServer.start(AF_INET, TCP, 5005);
    return 0;
}

客户端

Client.h

#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <net/if.h>
enum ServerType{
    TCP,
    UDP,
};
class Client{
public:
    Client();
    ~Client();
    bool create(int domain, ServerType serverType);
    bool connectServer(int domain, const char *ip, short int port);
    bool sendMsg(const char *msg);
    bool closeClient();
private:
    int client_fd;
    sockaddr_in addr;
};

Client.cpp

#include "Client.h"

Client::Client(){
    client_fd = -1;
}   

Client::~Client(){

}

bool Client::create(int domain, ServerType serverType){
    if(serverType == ServerType::TCP){
        client_fd = socket(domain, SOCK_STREAM, 0);
    }
    else{
        client_fd = socket(domain, SOCK_DGRAM, 0);
    }
    if(client_fd < 0){
        printf("failed to create client\n");
        return false;
    }
    
}

bool Client::connectServer(int domain, const char *ip, short int port){
    if(client_fd < 0){
        return false;
    }
    sockaddr_in server_addr;
    server_addr.sin_family = domain;
    server_addr.sin_addr.s_addr = inet_addr(ip);
    server_addr.sin_port = htons(port);
    if(connect(client_fd, (sockaddr *)&server_addr, sizeof(server_addr)) < 0){
        printf("failed to connect to server\n");

        return false;
    }

}
bool Client::sendMsg(const char *msg){
    if(send(client_fd, msg, strlen(msg), 0) < 0){
        printf("send msg error\n");
        return false;
    }
    return true;

}

bool Client::closeClient(){
    if(client_fd > 0){
        close(client_fd);
    }
}

tcpClient.cpp

#include "Client.h"

int main(){

    Client tcpClient;
    tcpClient.create(AF_INET, TCP);
    tcpClient.connectServer(AF_INET, "127.0.0.1", 5005);
    tcpClient.sendMsg("hello world");
    tcpClient.closeClient();
    return 0;
}

遇到的问题

服务端accept调用出现错误:invalid client fd: -1, Bad file descriptor

问题分析,子进程中关闭了listenfd,但是没有调用exit退出子进程,导致子进程执行while循环,继续调用accept函数,但此时子进程中的listenfd已经关闭,所以出现Bad file descriptor错误

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值