Chinaunix首页 | 论坛 | 博客
  • 博客访问: 338724
  • 博文数量: 45
  • 博客积分: 669
  • 博客等级: 上士
  • 技术积分: 675
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-27 17:59
文章分类
文章存档

2015年(5)

2014年(6)

2013年(4)

2012年(30)

分类: LINUX

2012-07-23 22:08:20

本程序分为服务端与客户端,服务器建立一个共享内存区,用于存贮各个客户端发送过来的消息,服务器接收一个客户端登陆后,即开启一个子进程,原父进程返回等待新客户的登陆,子进程用于接收客户的消息,并把共享内存里面的全部的内容发送给客户端。为了便于处理数据的方便,在处理客户消息的子进程中再创建一个子进程,一个用于接收子进程消息,存于共享内存区;另一个子进程用于发送共享内存给客户端。

 

客户端接收到共享内存的内容后,根据实际情况显示共享内存里面的内容。后登陆的用户可以看到前面用户的聊天内容。

本设计锻炼了linux中socket的基本应用,服务端建立套接字的大致步骤:

1,建立socket。

2,bind 绑定特定的端口。

3,listen 监听特定的端口。

4,accept,当有客户端连接服务器端口时,accept接收信息,并返回新的套接字描述符,提供给操作

5,根据实际需求,write,read,send,recv等操作

6,关闭套接字。

客户端大致步骤:

1,创建socket.

2,根据服务器地址,connect连接到特定服务器。

3,write,read等读写操作。

4,关闭套接字。

 

在程序调试过程中,要特别注意清空常用的载体。留意sizeof和strlen的区别。

留意各进程之间的关系的梳理,各循环的起始条件,运行情况。

 
服务器:server.c

点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/socket.h> // 包含套接字函数库
  3. #include <stdio.h>
  4. #include <netinet/in.h> // 包含AF_INET相关结构
  5. #include <arpa/inet.h> // 包含AF_INET相关操作的函数
  6. #include <unistd.h>
  7. #include<string.h>
  8. #include<stdlib.h>
  9. #include<fcntl.h>
  10. #include<sys/shm.h>

  11. #define PORT 8888;

  12. #define MYKEY 12345
  13. #define SIZE 10240

  14. int main()
  15. {
  16.     int shmid;
  17.     char *shmaddr; //定义子进程共用的共享内存
  18.     shmid = shmget(MYKEY, SIZE, IPC_CREAT | 0600);
  19.     shmaddr= (char *) shmat(shmid, 0, 0);
  20.    
  21.     if(shmid==-1)
  22.     {
  23.         printf("shmid error\n");
  24.     }
  25.     memset(shmaddr,0,SIZE);
  26.    
  27.     int i=0;
  28.     char buf[100];
  29.     memset(buf,0,100);
  30.    
  31.    
  32.     int server_sockfd,client_sockfd;
  33.     int server_len,client_len;
  34.    
  35.     struct sockaddr_in server_sockaddr,client_sockaddr;
  36.    
  37.    
  38.     server_sockfd = socket(AF_INET,SOCK_STREAM, 0); // 定义套接字类型
  39.    
  40.     server_sockaddr.sin_family=AF_INET;
  41.     server_sockaddr.sin_port=PORT;
  42.     server_sockaddr.sin_addr.s_addr=INADDR_ANY;
  43.    
  44.     server_len=sizeof(server_sockaddr);
  45.    
  46.     //允许重复使用本地地址和套接字绑定
  47.     int j=1;
  48.     setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&j,sizeof(j));
  49.    
  50.     //绑定端口
  51.     if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,server_len)==-1)
  52.     {
  53.         perror("bind:");
  54.         exit(1);
  55.     }
  56.    
  57.    
  58.     if(listen(server_sockfd,5)==-1)
  59.     {
  60.         perror("listen:");
  61.         exit(1);
  62.     }
  63.     printf("Listening...\n");
  64.    
  65.     client_len=sizeof(client_sockaddr);
  66.    
  67.     pid_t ppid,pid;
  68.   
  69.    while(1)
  70.    {
  71.     if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&client_sockaddr,&client_len))==-1)
  72.         {
  73.              perror("accept error:");
  74.              exit(1);
  75.         }
  76.    
  77.     printf("%s登录服务器\n",inet_ntoa(client_sockaddr.sin_addr));
  78.    
  79.     ppid=fork();
  80.    
  81.     if(ppid==-1)
  82.     {
  83.         printf("fork 1 failed:");
  84.     }
  85.    
  86.     if(ppid==0) //子进程用于接收客户端信息并发送
  87.     {
  88.         pid=fork();
  89.         if(pid==-1)
  90.         {
  91.             printf("fork 2 failed:");
  92.             exit(1);
  93.         }
  94.     
  95.      int recvbytes;
  96.          
  97.         if(pid==0) //子子进程用于接收消息
  98.         {
  99.             while(1)
  100.             {
  101.                
  102.                if((recvbytes=recv(client_sockfd,buf,100,0))==-1)
  103.                {
  104.                     perror("read client_sockfd failed:");
  105.                   
  106.                }
  107.                // printf("recvbytes=%d\n",recvbytes);
  108.                 usleep(10000);
  109.                printf("client send buf=%s\n",buf);
  110.                
  111.                 for(i=0;i<1000;i++)
  112.                 {
  113.                     if(*(shmaddr+100*i)==0)
  114.                     {
  115.                         strcpy(shmaddr+100*i,buf);
  116.                         break;
  117.                     
  118.                     }
  119.                 }
  120.                
  121.                
  122.             }
  123.         }
  124.        
  125.         if(pid>0) //子进程用于发送消息
  126.         {
  127.            while(1)
  128.             {
  129.                 if(*(shmaddr+i*100)!=0)
  130.                {
  131.                    // strcpy(&buf,shmaddr+100*i);
  132.                 
  133.                   // buf++;
  134.                     write(client_sockfd,shmaddr,SIZE);
  135.                    // send(client_sockfd,buf,strlen(buf),0);
  136.                   
  137.                  // printf("the server is send buf=%c",buf);
  138.                   // printf("send client :%s\n",(shmaddr+i*100)) ;
  139.                     i++;
  140.                    
  141.                 }
  142.             }
  143.        
  144.         }
  145.       
  146.     }
  147.    
  148.    
  149.     if(ppid>0) //总父进程返回等待接收消息
  150.     {
  151.         close(client_sockfd);
  152.     }
  153.        
  154.     
  155.     }

  156. }
 

客户端:client.c

点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/socket.h> // 包含套接字函数库
  3. #include <stdio.h>
  4. #include <netinet/in.h> // 包含AF_INET相关结构
  5. #include <arpa/inet.h> // 包含AF_INET相关操作的函数
  6. #include <unistd.h>
  7. #include<string.h>
  8. #include<time.h>

  9. #define PORT 8888
  10. #define IP_ADDR "192.168.110.185"

  11. #define SIZE 10240

  12. int main()
  13. {
  14.      
  15.     struct tm *timeptr;
  16.     time_t timeval;
  17.     char tm[50];
  18.     //(void)time(&timeval);
  19.    
  20.     //printf("the date is %s\n",ctime(&timeval));
  21.    // printf("The time is %s\n",tm);

  22.     int sockfd; // 用于保存客户套接字标识符
  23.     int len; // 用于客户消息长度
  24.     struct sockaddr_in address; // 定义客户套接字地址

  25.     int result;
  26.    

  27.     sockfd = socket(AF_INET,SOCK_STREAM, 0); // 定义套接字类型
  28.     address.sin_family = AF_INET; // 定义套接字地址中的域
  29.    
  30.     address.sin_addr.s_addr = inet_addr(IP_ADDR); // 定义套接字地址
  31.    
  32.     address.sin_port = htons(PORT); // 定义套接字端口
  33.     char buf[100]; // 定义要传送的消息
  34.     memset(buf,0,100);
  35.     char str[90]; //存贮输入的语句
  36.    
  37.     char shmaddr[SIZE]; //接受服务器发送的全部聊天数据
  38.     int i=0;
  39.    
  40.     char myname[100];
  41.     char say[10]={"说:"};
  42.     printf("欢迎来到聊天室,请输入你的姓名:\n");
  43.     scanf("%s",myname);
  44.    
  45.    
  46.   
  47.    len = sizeof(address);
  48.    result = connect(sockfd, (struct sockaddr *) &address, len); // 请求连接

  49.    if (result == -1)
  50.     {
  51.       perror("Connect failed");
  52.       return 1;
  53.     }
  54.     printf("%s成功登录服务器:\n",myname);
  55.    

  56.     pid_t pid;
  57.    
  58.     pid=fork();
  59.     if(pid==-1)
  60.     {
  61.         printf("fork failed");
  62.     }
  63.    
  64.     int sendbytes=0;
  65.  
  66.     if(pid==0) //子进程用于发送数据
  67.     {
  68.        while(1)
  69.         {
  70.                 printf("请输入语句:\n");
  71.                
  72.                 scanf("%s",str);
  73.                
  74.                 (void)time(&timeval);
  75.                 strcpy(tm,ctime(&timeval));
  76.                
  77.                 strcpy(buf,myname); //姓名传入buf中
  78.                 strcat(buf,tm); //时间传入buf中
  79.                 strcat(buf,say);
  80.                 strcat(buf,str); //语句传入bufz中
  81.               
  82.                 //read(0,buf,strlen(buf));
  83.               
  84.                 // send(sockfd,buf,strlen(buf),0);
  85.                 // getchar();
  86.                
  87.                  if((sendbytes=write(sockfd, buf, 100))==-1)
  88.                  {
  89.                     perror("send to server failed:");
  90.                  } // 向服务器传送消息
  91.                 
  92.                 // printf("sendbytes=%d\n",sendbytes);
  93.                // printf("buf=%s\n",buf);
  94.                // printf("input buf=%s\n",buf);
  95.                  usleep(1000);
  96.                 
  97.                 memset(buf,0,100);
  98.                 memset(tm,0,50);
  99.         }
  100.     }
  101.    
  102.     if(pid>0) //父进程用于接受消息并读取
  103.     {
  104.         while(1)
  105.         {
  106.             read(sockfd,shmaddr,SIZE);
  107.           // printf("server send shmaddr=%s\n",shmaddr);
  108.            
  109.             if(*(shmaddr+i*100)!=0)
  110.             {
  111.                 printf("%s\n",(shmaddr+i*100)) ;
  112.                 i++;
  113.             
  114.             }
  115.            
  116.             usleep(1000);
  117.         }
  118.    
  119.        
  120.     }
  121.     close(sockfd);
  122.     return 0;

  123. }



 

 

阅读(3837) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~