Linux平台C语言Socket编程练习之多进程服务器

作者: 分类: 学习记录 评论: 暂无 时间: 2016-11-25 浏览: 1,128 次

0x00 要求

采用多进程并发服务器技术,服务器可以同时接受多个客户的请求。具体要求如下:

服务端

接收并显示与之连接的客户端的名称;

接收客户端发来的字符串,显示出来,并对字符串做反转处理,最后将处理后的字符串发回给客户。

客户端

根据客户输入的服务器IP地址,向服务器发起建立连接的请求;

接收客户输入的客户端名称,并把该客户端名称发给服务器;

接收客户输入的字符串,将字符串发送给服务器;

接收服务器发回的反转处理后的字符串并显示。继续接受客户输入的字符串,直到用户输入quit时退出。

0x01 代码

服务端

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

#define PORT 1234
#define BACKLOG 5
#define MAXDATASIZE 100

void pro_cli(int connfd,struct sockaddr_in client);

int main()
{
    int listenfd;
    int connfd;
    socklen_t client_len;
    pid_t pid;
    struct sockaddr_in server;
    struct sockaddr_in client;

    if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        perror("socket() failed.");
        exit(1);
    }

    int opt=SO_REUSEADDR;
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    bzero(&server,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(PORT);
    server.sin_addr.s_addr=htonl(INADDR_ANY);

    if(bind(listenfd,(struct sockaddr *)&server,sizeof(server))==-1)
    {
        perror("bind() failed.");
        exit(1);
    }

    if(listen(listenfd,BACKLOG)==-1)
    {
        perror("listen() failed.");
        exit(1);
    }

    client_len=sizeof(client);

    while(1)
    {
        if(((connfd=accept(listenfd,(struct sockaddr *)&client,&client_len))==-1))
        {
            perror("accept() failed.");
            exit(1);
        }

        if((pid=fork())>0)
        {
            close(connfd);
            continue;
        }
        else if(pid==0)
        {
            close(listenfd);
            pro_cli(connfd,client);
            exit(0);
        }
        else
        {
            printf("fork() failed.");
            exit(0);
        }
        close(listenfd);
    }
    return 0;
}

void pro_cli(int connfd,struct sockaddr_in client)
{
    ssize_t send_num;
    ssize_t recv_num;
    char send_buf[MAXDATASIZE];
    char recv_buf[MAXDATASIZE];
    char client_name[MAXDATASIZE];
    char wel_msg[]="[!] Welcome,you can input 'quit' to exit :)  ";


    printf("[!] You got a connection from client IP: <%s> PORT: <%d> \n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));

    if((send(connfd,wel_msg,strlen(wel_msg),0))==-1)
    {
        perror("send welcome messages fail.");
        exit(1);
    }
    if((recv_num=recv(connfd,client_name,MAXDATASIZE,0))==-1)
    {
        perror("recv() failed.");
        close(connfd);
        return;
    }
    if(recv_num==0)
    {
        printf("[!] Client disconnected.\n");
        close(connfd);
    }
    client_name[recv_num-1]='\0';
    printf("[*] Client name: <%s> \n",client_name);
    while(1)
    {
        if((recv_num=recv(connfd,recv_buf,MAXDATASIZE,0))==-1)
        {
            perror("recv() error.");
            exit(1);
        }
        recv_buf[recv_num-1]='\0';
        printf("[*] Received string: '%s' from client: <%s> \n ",recv_buf,client_name);

        size_t len=strlen(recv_buf);
        for(int i=0; i<(len/2); ++i)
        {
            char tmp=recv_buf[i];
            recv_buf[i]=recv_buf[len-1-i];
            recv_buf[len-1-i]=tmp;
        }

        strcpy(send_buf,recv_buf);
        printf("[>] Send reverse string: '%s' to client: <%s> \n",send_buf,client_name);

        if((send_num=send(connfd,send_buf,MAXDATASIZE,0))==-1)
        {
            perror("send() error.");
            exit(1);
        }

        if(!strcmp(send_buf,"tiuq"))
        {
            printf("[!] Client <%s> have disconnected! \n",client_name);
            break;
        }
    }
    close(connfd);
    return;
}

客户端

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

#define PORT 1234
#define MAXDATASIZE 100

int main(int argc,char *argv[])
{
    int sockfd;
    ssize_t send_num;
    ssize_t recv_num;
    char wel_msg[MAXDATASIZE];
    char cli_name[MAXDATASIZE];
    char recv_buf[MAXDATASIZE];
    char send_buf[MAXDATASIZE];
    struct hostent *he;
    struct sockaddr_in server;
    if(argc!=2)
    {
        printf("Usage:%s <IP Adress>\n",argv[0]);
        exit(1);
    }
    if((he=gethostbyname(argv[1]))==NULL)
    {
        printf("gethostbyname() failed.");
        exit(1);
    }
    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        printf("socket() failed.");
        exit(1);
    }
    bzero(&server,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(PORT);
    server.sin_addr=*((struct in_addr *)he->h_addr);

    if(connect(sockfd,(struct sockaddr *)&server,sizeof(server))==-1)
    {
        printf("connect() failed.");
        exit(1);
    }
    if ((recv(sockfd,wel_msg,MAXDATASIZE,0))==-1)
    {
        perror("[!] Receive welcome message fail.");
        exit(1);
    }
    wel_msg[sizeof(wel_msg)]='\0';
    printf("%s\n", wel_msg);
    printf("[*] Input client name:");
    scanf("%s",cli_name);
    if((send_num=send(sockfd,cli_name,MAXDATASIZE,0))==-1)
    {
        perror("send() error.");
        exit(1);
    }

    while(1)
    {
        printf("[*] Input string:");
        scanf("%s",send_buf);
        send_buf[strlen(send_buf)]='\0';

        if((send_num=send(sockfd,send_buf,MAXDATASIZE,0))==-1)
        {
            perror("send() error.");
            exit(1);
        }

        if((recv_num=recv(sockfd,recv_buf,MAXDATASIZE,0))==-1)
        {
            perror("recv() error.");
            exit(1);
        }

        printf("[>] Received reverse string:%s\n",recv_buf);
        if(!strcmp(recv_buf,"tiuq"))
        {
            break;
        }
    }
    close(sockfd);
    return 0;
}

0x02 演示

服务端

多进程服务端.gif

客服端1

客户端1.gif

客户端2

客户端2.gif

0x03 心得

注意fork函数的用法:

pid_t pid;
if((pid=fork())>0)/*产生子进程*/
{    /*父进程处理过程,父进程关闭父进程的已连接套接字描述符,跳出while循环继续侦听下一个客户的请求*/
    close(connfd);
    continue;
}
else if(pid==0)
{    /*子进程处理过程,子进程关闭子进程的套接字描述符,调用子进程处理函数pro_cli函数*/
    close(listenfd);
    pro_cli(connfd,client);/*传入子进程的已连接socket描述符和客户端的套接字地址结构*/
    exit(0);/*子进程必须调用exit函数结束退出*/
}
else
{    /*fork函数调用失败结束处理*/
    printf("fork() failed.");
    exit(0);
}

转载请注明来自4ido10n博客的Linux平台C语言Socket编程练习之多进程服务器,否则保留追究文章版权的权利!

订阅本站(RSS)

添加新评论