linux网络编程并发进程,select和epoll(一)

11 篇文章 0 订阅

linux中学习网络编程,最先开始的莫过于写一个client/server程序作为练习。我最近也在写这些东西,还得在这里感谢公司老大, 给了我这个实习生学习的机会,自己很菜啦


首先:我们了解到在server端最原始也最简单的方式莫过于第一步建立一个socket,第二步将socket与IP地址和端口进行绑定bind,第三步监听端口,等待client端和server的connect,第四步accept 接受连接,和client建立了网络连接,第五步如果需要接受client端数据,并发送数据,则使用send,recv函数对或者使用read/write函数对。

这种最简单的服务器只能处理client的一次请求,如果多个client需要与serve连接,则必须等待。这个example仅适用于练习,对于实际的应用来讲没有什么用处。

如果想要server处理多个请求,最先想到的改进方法莫过于使用多进程了,下面给出个例子,本人是使用c++技术写的,所以封装了一个类:

server.h文件:

#ifndef TEST_PROJECT_SERVER_H_
#define TEST_PROJECT_SERVER_H_

#define MY_PORT 7800
#define LISTEN_NUM 10

class Server{
    public:
        Server(){}
        void ForkServer(const int &send_message);
};

#endif // end TEST_PROJECT_SERVER_H_

server.cc文件:

#include "server.h"


#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>


void Server::ForkServer(const int &send_message){
    int m_listen_sock_fd, m_data_sock_fd;
    struct sockaddr_in server_addr; // server address
    struct sockaddr_in client_addr; // client address
    unsigned int sin_size;


    if ((m_listen_sock_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket error\n");
        exit(1);
    }
    server_addr.sin_family=PF_INET;
    server_addr.sin_port=htons(MY_PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(server_addr.sin_zero), 0);


    if (bind(m_listen_sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind");
        exit(1);
    }


    if (listen(m_listen_sock_fd, LISTEN_NUM) == -1) {
        perror("listen error");
        exit(1);
    }


    while (1) {
        sin_size = sizeof(struct sockaddr_in);
        if ((m_data_sock_fd = accept(m_listen_sock_fd, (struct sockaddr *)&client_addr, &sin_size)) == -1) {
            perror("accept");
            continue;
        }
        printf("server: got connection from %s\n", inet_ntoa(client_addr.sin_addr));
        if (!fork()) { // childprocess code
            if (send(m_data_sock_fd, &send_message, sizeof(int), 0) == -1) {
                perror("send");
                close(m_data_sock_fd);
                exit(0);
            }
        }
        close(m_data_sock_fd); // parent process don't need child process
        waitpid(-1,NULL,WNOHANG);// wait for childprocess end, delete all resources
    }
}


int main (int argc, char *argv[]) {
    Server server;
    server.ForkServer(3);
}


另外为了方便测试这里也把client端的代码贴出来,无论server如何变化,client都可以用:


#ifndef TEST_PROJECT_CLIENT_H_
#define TEST_PROJECT_CLIENT_H_

#define MY_PORT 7800


class Client{
    public:
        Client(){}
        void ForkClient(const char *host_name);
};

#endif // end TEST_PROJECT_CLIENT_H_


#include "client.h"


#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>


void Client::ForkClient(const char *host_name){
    int sockfd, numbytes;
    int result = 0;
    struct hostent *he;
    struct sockaddr_in their_addr;


    if((he=gethostbyname(host_name))==NULL) {
    }
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
    their_addr.sin_family=PF_INET;
    their_addr.sin_port=htons(MY_PORT);
    their_addr.sin_addr = *((struct in_addr *)he->h_addr);
    bzero(&(their_addr.sin_zero),0);
    if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect");
        exit(1);
    }
    char send_message[] = "hello server";
    if (send(sockfd, send_message, sizeof(send_message), 0) == -1) {
        perror("send error");
        close(sockfd);
        exit(0);
    }


    if ((numbytes=recv(sockfd, &result, sizeof(int), 0)) == -1) {
        perror("recv");
        exit(1);
    }
    printf("Received: %d\n",result);
    close(sockfd);
}


int main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr,"usage: %s hostname\n", argv[0]);
        exit(1);
    }
    if(argv[1] == NULL) {
        herror("gethostbyname");
        exit(1);
    }


    Client client;
    client.ForkClient(argv[1]);
    return 0;
}


从上述例子中可以看到虽然使用了多进程方式,但是改server还是block类型的,改例子并没有解决阻塞问题。

reference:

Linux下各类TCP网络服务器的实现源代码


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值