Socket通信中的多进程编程实例

来源:互联网 发布:linux 网络服务器 编辑:程序博客网 时间:2024/06/06 00:15

1  需求描述:

(1)Linux下编写。

(2)创建一个服务器、若干个客户端。

(3)用户可以通过客户端输入文字向服务器发送消息。

(4)服务器端接收到客户端发送的数据,将用户输入的内容在服务器上打印出来,并原样返回。

2  相关基础

2.1 套接字Socket通信编程

2.1.1 TCP/IP通信过程:  

图2.1.1 TCP/IP通信过程

 

2.1.2 UDP通信过程:

图2.1.2 UDP通信过程

 

2.2 fork多进程编程

fork,在英语中意思是分叉的意思。Linux函数fork(void)被定义在#include<sys/types.h>中,调用成功时,返回两个值,子进程返回0,父进程返回子进程的ID,出错返回-1。子进程是父进程的副本,它将获得父进程的数据空间、堆、栈等资源的副本并且拥有自己独立的地址空间。

以下是一个fork的简单例子。

 

fork实例#include<sys/types.h>#include<unistd.h>#include<stdio.h>int main(int argc, char ** argv ){    int pid = fork();    if (-1 == pid)    {        printf("error!");  //出错    }    else if(0 == pid )    {        printf("This is the child process!");  //子进程    }    else    {        printf("This is the parent process! child process id = %d",         pid);  //父进程,返回的是子进程的ID    }    return 0;}

3  设计

3.1 框架设计

 

图3.1 框架设计

       本文使用TCP进行通信。

3.2 代码设计

       套接口的通信一般使用read( )和write( )。这里使用send( )和recv( ),因为这一对函数可以更好地控制数据传输。 

 

图3.2 代码设计

4  详细代码

4.1 服务器端代码

服务器端代码#include <sys/types.h>#include <sys/socket.h>                         // 包含套接字函数库#include <stdio.h>#include <netinet/in.h>                         // 包含AF_INET相关结构#include <arpa/inet.h>                      // 包含AF_INET相关操作的函数#include <unistd.h>#include<string.h>#include<stdlib.h>#include<fcntl.h>#include<sys/shm.h>#define MYPORT    8887  #define MYKEY   12345#define SIZE    10240int main(){        char buf[100];    memset(buf,0,100);          int server_sockfd,client_sockfd;       socklen_t server_len,client_len;       struct sockaddr_in server_sockaddr,client_sockaddr;       printf("\n======================server initialization======================\n");     server_sockfd = socket(AF_INET,SOCK_STREAM, 0); // 定义套接字类型       server_sockaddr.sin_family = AF_INET;    server_sockaddr.sin_port = htons(MYPORT);    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);     server_len = sizeof(server_sockaddr);       //允许重复使用本地地址和套接字绑定    int on = 1;    setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));       //绑定端口    if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,server_len)==-1)    {        perror("bind");        exit(1);    }          //监听端口    if(listen(server_sockfd,5) == -1)    {        perror("listen");        exit(1);       }          client_len = sizeof(client_sockaddr);       pid_t ppid,pid;      while(1)    {          if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&client_sockaddr,&client_len))==-1)        {             perror("accept error");             exit(1);        }        else        {            send(client_sockfd,"You have connect Server!",strlen("You have connect Server!"),0);        }           printf("\n%s:%d Login server!\n\n",inet_ntoa(client_sockaddr.sin_addr), ntohs(client_sockaddr.sin_port));           ppid = fork();    //创建子进程           if(ppid == -1)        {            printf("fork 1 failed:");        }        else if(ppid == 0)    //子进程用于接收客户端信息并发送        {                       int recvbytes;            pid = fork();    //再次创建子进程                        if(pid == -1)            {                printf("fork 2 failed:");                exit(1);            }            else if(pid == 0) //子进程的子进程用于接收消息            {                              while(1)                {                              bzero(buf,100);                    if((recvbytes = recv(client_sockfd,buf,100,0))==-1)                    {                        perror("read client_sockfd failed:");                    }                    else if(recvbytes != 0)                    {                                                buf[recvbytes] = '\0';                        usleep(10000);                        printf("%s:%d said:%s\n",inet_ntoa(client_sockaddr.sin_addr), ntohs(client_sockaddr.sin_port), buf);                        //将客户端发送过来的消息发回给客户                        if(send(client_sockfd,buf,recvbytes,0)==-1){                             perror("send error");                            break;                        }                    }                }            }            else if(pid>0)  //此时的id为子进程id             {                }            }         else if(ppid>0)        {                         //总父进程中关闭client_sockfd(因为有另一个副本在子进程中运行了)返回等待接收消息            close(client_sockfd);        }        }    return 0;}

4.2 客户端代码


客户端代码#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/wait.h> #include<unistd.h> #include <arpa/inet.h> #define SERVER_PORT 8887 /* 客户机连接远程主机的端口 */ #define MAXDATASIZE 100 /* 每次可以接收的最大字节 */ #define SERVER_IP "192.168.11.8" /* 服务器的IP地址 */int main(){     int sockfd, numbytes;     char buf[MAXDATASIZE];     struct sockaddr_in server_addr;    printf("\n======================client initialization======================\n");     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)     {         perror("socket");         exit(1);     }     server_addr.sin_family = AF_INET;     server_addr.sin_port = htons(SERVER_PORT);     server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);    bzero(&(server_addr.sin_zero),sizeof(server_addr.sin_zero));     if (connect(sockfd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) == -1)     {         perror("connect");        exit(1);     }    //循环输入文字    while(1)    {                bzero(buf,MAXDATASIZE);        printf("\nBegin receive...\n");        if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1)                {             perror("recv");            exit(1);         }        else if (numbytes > 0)                {            int len, bytes_sent;            buf[numbytes] = '\0';            printf("Received: %s\n",buf);                        printf("Send:");            char *msg;            scanf("%s",msg);                        len = strlen(msg);            //发送至服务器            if(send(sockfd,msg,len,0) == -1)            {                 perror("send error");            }        }        else        {            //numbytes=0,表示socket已断开            printf("soket end!\n");        }            }    close(sockfd);     return 0;}

 

5  运行结果

  Linux下进行编译:

    gcc Server.c -o server

    gcc Client.c -o client

 

运行结果

客户端1: 

图5.1 客户端1运行结果

客户端2:

 图5.2 客户端2运行结果

服务器端: 


本文转自 : http://www.cnblogs.com/jamiechu/archive/2012/12/08/2808165.html

原创粉丝点击