刘喆君

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

2018-2019-1 20165205 实验三 并发进程

任务一:

  • 学习使用Linux命令wc(1)

  • 基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
    客户端传一个文本文件给服务器
    服务器返加文本文件中的单词数

客户端代码如下:

#include<netinet/in.h>   // sockaddr_in  
#include<sys/types.h>    // socket  
#include<sys/socket.h>   // socket  
#include<stdio.h>        // printf  
#include<stdlib.h>       // exit  
#include<string.h>       // bzero  

#define SERVER_PORT 165205  
#define BUFFER_SIZE 1024  
#define FILE_NAME_MAX_SIZE 512  
#define BEGIN 1;

int main()  
{  	
struct sockaddr_in client_addr;  
bzero(&client_addr, sizeof(client_addr));  
client_addr.sin_family = AF_INET;  
client_addr.sin_addr.s_addr = htons(INADDR_ANY);  
client_addr.sin_port = htons(0);  

int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);  
if(client_socket_fd < 0)  
{  
    perror("Create Socket Failed:");  
    exit(1);  
}  

if(-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))  
{  
    perror("Client Bind Failed:");  
    exit(1);  
}  

struct sockaddr_in server_addr;  
bzero(&server_addr, sizeof(server_addr));  
server_addr.sin_family = AF_INET;  
if(inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) == 0)  
{  
    perror("Server IP Address Error:");  
    exit(1);  
}  
server_addr.sin_port = htons(SERVER_PORT);  
socklen_t server_addr_length = sizeof(server_addr);  

if(connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)  
{  
    perror("Can Not Connect To Server IP:");  
    exit(0);  
}  

char file_name[FILE_NAME_MAX_SIZE+1];  
bzero(file_name, FILE_NAME_MAX_SIZE+1);  

printf("Please Input File Name On Client:\t");
scanf("%s", file_name);  

char buffer[BUFFER_SIZE];  
bzero(buffer, BUFFER_SIZE);  
strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));  

if(send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)  
{  
    perror("Send File Name Failed:");  
    exit(1);  
}  

    FILE *fp = fopen(file_name, "r");  
    if(NULL == fp)  
{  
    printf("File:%s Not Found\n", file_name);  
}  
else  
{  
    bzero(buffer, BUFFER_SIZE);  
    int length = 0;  
    while((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)  
    {  
        if(send(client_socket_fd, buffer, length, 0) < 0)  
        {  
            printf("Send File:%s Failed./n", file_name);  
            break;  
        }  
        bzero(buffer, BUFFER_SIZE);  
    }  

    fclose(fp);  
    printf("File:%s Transfer Successful!\n", file_name);  
}  

char s[50];
scanf("%s",s);
send(client_socket_fd,"OK",50,0);

char recvdata[sizeof(int)+1];
recv(client_socket_fd,recvdata,sizeof(int),0);
recvdata[sizeof(int)]='\0';
int words=atoi(recvdata);
close(client_socket_fd);  
return 0;  
}

服务器端代码如下:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/time.h> 
  
#define BUFLEN 1024 
#define PORT 6666
///#define LISTNUM 20

int main() 
{ 
    int sockfd, newfd; 
    struct sockaddr_in s_addr, c_addr; 
    char buf[BUFLEN]; 
    socklen_t len; 
    unsigned int port, listnum; 
    fd_set rfds; 
    struct timeval tv; 
    int retval,maxfd; 
  
    /*建立socket*/ 
    if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){ 
    perror("socket"); 
    exit(errno); 
}else 
    printf("socket create success!\n"); 
memset(&s_addr,0,sizeof(s_addr)); 
s_addr.sin_family = AF_INET; 
s_addr.sin_port = htons(PORT); 
s_addr.sin_addr.s_addr = htonl(INADDR_ANY); 

/*把地址和端口帮定到套接字上*/ 
if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){ 
    perror("bind error"); 
    exit(errno); 
}else 
    printf("bind success!\n"); 
/*侦听本地端口*/ 
if(listen(sockfd,5) == -1){ 
    perror("listen error"); 
    exit(errno); 
}else 
    printf("the server is listening!\n"); 
while(1){ 
    printf("*****************聊天开始***************\n"); 
    len = sizeof(struct sockaddr); 
    if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) == -1){ 
        perror("accept"); 
        exit(errno); 
    }else 
        printf("正在与您聊天的客户端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port)); 
    while(1){ 
        FD_ZERO(&rfds); 
        FD_SET(0, &rfds); 
        maxfd = 0; 
        FD_SET(newfd, &rfds); 
        /*找出文件描述符集合中最大的文件描述符*/ 
        if(maxfd < newfd) 
            maxfd = newfd; 
        /*设置超时时间*/ 
        tv.tv_sec = 6; 
        tv.tv_usec = 0; 
        /*等待聊天*/ 
        retval = select(maxfd+1, &rfds, NULL, NULL, &tv); 
        if(retval == -1){ 
            printf("select出错,与该客户端连接的程序将退出\n");  
            break; 
        }else if(retval == 0){ 
            printf("waiting...\n"); 
            continue; 
        }else{ 
            /*服务器输入信息*/ 
            if(FD_ISSET(0, &rfds)){ 
        
                /******发送消息*******/ 
                memset(buf,0,sizeof(buf)); 
                
                fgets(buf,BUFLEN,stdin); 
                
                //fputs(buf,stdout); 
                if(!strncasecmp(buf,"quit",4)){ 
                    printf("server 请求终止聊天!\n"); 
                    break; 
                } 
                    len = send(newfd,buf,strlen(buf),0); 
                if(len > 0) 
                    printf("\t消息发送成功:%s\n",buf); 
                else{ 
                    printf("消息发送失败!\n"); 
                    break; 
                } 
            } 
            /*客户端发来了消息*/ 
            if(FD_ISSET(newfd, &rfds)){ 
                /******接收消息*******/ 
                memset(buf,0,sizeof(buf)); 
                /*fgets函数:从流中读取BUFLEN-1个字符*/ 
                len = recv(newfd,buf,BUFLEN,0); 
                if(len > 0) 
                    printf("客户端发来的信息是:%s\n",buf); 
                else{ 
                    if(len < 0 ) 
                        printf("接受消息失败!\n"); 
                    else 
                        printf("客户端退出了,聊天终止!\n"); 
                    break; 
                } 
            } 
        } 
    } 
    /*关闭聊天的套接字*/ 
    close(newfd); 
    /*是否退出服务器*/ 
    printf("服务器是否退出程序:y->是;n->否? "); 
    bzero(buf, BUFLEN); 
    fgets(buf,BUFLEN, stdin); 
    if(!strncasecmp(buf,"y",1)){ 
        printf("server 退出!\n"); 
        break; 
    } 
} 
/*关闭服务器的套接字*/ 
close(sockfd); 
return 0; 
}
  • 实验截图

任务二:

  • 使用多线程实现wc服务器并使用同步互斥机制保证计数

在实验之前,我学习了关于多线程函数pthread的一些知识

1.pthread_creat函数

它的作用是创建一个新线程,使用方法如下:

#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); 

第一个参数是指向pthread_t类型的指针。线程被创建时 这个指针指向的变量将被写入一个标识符(线程ID)我们用该标识符来引用新线程。

第二个参数用于设置线程的属性,一般不需要特殊的属性,所以只需要设置该参数为NULL。

最后两个参数,分别告诉新线程将要启动执行的函数和传递给该函数的参数。

pthread_create函数在成功调用时返回0,如果失败则返回失败码

2.pthread_exit函数

线程通过调用pthread_exit函数终止执行。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针

#include <pthread.h>
void pthread_exit(void *retval);

3.pthread_join函数

pthread_join函数的作用是等待某个线程的结束。其第一个参数指定了需要等待的线程ID,第二个参数是一个二级指针,它指向另一个指针,而后者指向线程的返回值。

#include <pthread.h>
int pthread_join(pthread_t th, void **thread_return);

4.pthread_self函数

每个线程都有一个在所属进程内标识自己的ID。线程ID由phtread_create返回,而且我们已经看到pthread_join也使用了线程ID来指定等待哪个线程。pthread_self的作用是返回自身的线程ID.

#include <pthread.h>
pthread_t pthread_self(void);

5.pthread_detach函数

一个线程或者是可汇合(joinable),或者是脱离的(detached)。当一个可汇合的线程终止时,它的线程ID和退出状态将留存到另一个线程对它调用pthread_join的返回值中。脱离的线程终止时,所有相关资源都被释放,我们不能等待它们终止。如果一个线程需要知道另一个线程什么时候终止,那就最好保持第二个线程的可汇合状态。

pthread_detach函数把指定的线程转变为脱离的状态。

#include <pthread.h>
int pthread_detach(pthread_t th);
  • 多线程客户端代码:

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <errno.h>
      #include <sys/socket.h>
      #include <arpa/inet.h>
      #include <netinet/in.h>
      #include <sys/types.h>
      #include <unistd.h>
      #include <sys/time.h>
    
      #define BUFLEN 1024
      #define PORT 6666
    
      int main(int argc, char **argv)
      {
      int sockfd;
      struct sockaddr_in s_addr;
      socklen_t len;
      unsigned int port;
      char buf[BUFLEN];
      fd_set rfds;
      struct timeval tv;
      int retval, maxfd; 
      
      if(argc != 2)
      {
          perror("Usage:./client <ipaddress>.");
          exit(errno);
      }
    
    
      /*建立socket*/
      if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
          perror("socket");
          exit(errno);
      }else
          printf("socket create success!\n");
    
    
      /*设置服务器ip*/
      memset(&s_addr,0,sizeof(s_addr));
      s_addr.sin_family = AF_INET;
       s_addr.sin_port = htons(PORT);
      if (inet_aton(argv[1], (struct in_addr *)&s_addr.sin_addr.s_addr) == 0) {
          perror(argv[1]);
          exit(errno);
      }
      /*开始连接服务器*/ 
      if(connect(sockfd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr)) == -1){
          perror("connect");
          exit(errno);
      }else
          printf("conncet success!\n");
    
      while(1){
          FD_ZERO(&rfds);
          FD_SET(0, &rfds);
          maxfd = 0;
          FD_SET(sockfd, &rfds);
          if(maxfd < sockfd)
              maxfd = sockfd;
          tv.tv_sec = 6;
          tv.tv_usec = 0;
          retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
          if(retval == -1){
              printf("select出错,客户端程序退出\n");
              break;
          }else if(retval == 0){
          printf("waiting...\n");
          continue;
      }else{
          /*服务器发来了消息*/
          if(FD_ISSET(sockfd,&rfds)){
              /******接收消息*******/
              bzero(buf,BUFLEN);
              len = recv(sockfd,buf,BUFLEN,0);
              if(len > 0)
                  printf("服务器发来的消息是:%s\n",buf);
              else{
                  if(len < 0 )
                      printf("接受消息失败!\n");
                  else
                      printf("服务器退出了,聊天终止!\n");
              break; 
              }
          }
          /*用户输入信息了,开始处理信息并发送*/
          if(FD_ISSET(0, &rfds)){ 
              /******发送消息*******/ 
              bzero(buf,BUFLEN);
              fgets(buf,BUFLEN,stdin);
             
              if(!strncasecmp(buf,"quit",4)){
                  printf("client 请求终止聊天!\n");
                  break;
              }
                  len = send(sockfd,buf,strlen(buf),0);
              if(len > 0)
                  printf("\t消息发送成功:%s\n",buf); 
              else{
                  printf("消息发送失败!\n");
                  break; 
              } 
          }
      }
    
      }
      /*关闭连接*/
      close(sockfd);
    
      return 0;
      }	
    
  • 多线程服务器代码:

      #include <stdio.h> 
      #include <stdlib.h> 
      #include <string.h> 
      #include <errno.h> 
      #include <sys/socket.h> 
      #include <arpa/inet.h> 
      #include <netinet/in.h> 
      #include <sys/types.h> 
      #include <unistd.h> 
      #include <sys/time.h> 
    
      #define BUFLEN 1024 
      #define PORT 6666
      ///#define LISTNUM 20
    
      int main() 
      { 
      int sockfd, newfd; 
      struct sockaddr_in s_addr, c_addr; 
      char buf[BUFLEN]; 
      socklen_t len; 
      unsigned int port, listnum; 
      fd_set rfds; 
      struct timeval tv; 
      int retval,maxfd; 
    
      /*建立socket*/ 
      if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){ 
          perror("socket"); 
          exit(errno); 
      }else 
          printf("socket create success!\n"); 
      memset(&s_addr,0,sizeof(s_addr)); 
      s_addr.sin_family = AF_INET; 
      s_addr.sin_port = htons(PORT); 
      s_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    
      /*把地址和端口帮定到套接字上*/ 
      if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){ 
          perror("bind error"); 
          exit(errno); 
      }else 
          printf("bind success!\n"); 
      /*侦听本地端口*/ 
      if(listen(sockfd,5) == -1){ 
          perror("listen error"); 
          exit(errno); 
      }else 
          printf("the server is listening!\n"); 
      while(1){ 
          printf("*****************聊天开始***************\n"); 
          len = sizeof(struct sockaddr); 
          if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) == -1){ 
              perror("accept"); 
              exit(errno); 
      }else 
          printf("正在与您聊天的客户端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port)); 
      while(1){ 
          FD_ZERO(&rfds); 
          FD_SET(0, &rfds); 
          maxfd = 0; 
          FD_SET(newfd, &rfds); 
          /*找出文件描述符集合中最大的文件描述符*/ 
          if(maxfd < newfd) 
              maxfd = newfd; 
          /*设置超时时间*/ 
          tv.tv_sec = 6; 
          tv.tv_usec = 0; 
          /*等待聊天*/ 
          retval = select(maxfd+1, &rfds, NULL, NULL, &tv); 
          if(retval == -1){ 
              printf("select出错,与该客户端连接的程序将退出\n");  
              break; 
          }else if(retval == 0){ 
              printf("waiting...\n"); 
              continue; 
          }else{ 
              /*服务器输入信息*/ 
              if(FD_ISSET(0, &rfds)){ 
          
                  /******发送消息*******/ 
                  memset(buf,0,sizeof(buf)); 
                  
                  fgets(buf,BUFLEN,stdin); 
                  
                  //fputs(buf,stdout); 
                  if(!strncasecmp(buf,"quit",4)){ 
                      printf("server 请求终止聊天!\n"); 
                      break; 
                  } 
                      len = send(newfd,buf,strlen(buf),0); 
                  if(len > 0) 
                      printf("\t消息发送成功:%s\n",buf); 
                  else{ 
                      printf("消息发送失败!\n"); 
                      break; 
                  } 
              } 
              /*客户端发来了消息*/ 
              if(FD_ISSET(newfd, &rfds)){ 
                  /******接收消息*******/ 
                  memset(buf,0,sizeof(buf)); 
                  /*fgets函数:从流中读取BUFLEN-1个字符*/ 
                  len = recv(newfd,buf,BUFLEN,0); 
                  if(len > 0) 
                      printf("客户端发来的信息是:%s\n",buf); 
                  else{ 
                      if(len < 0 ) 
                          printf("接受消息失败!\n"); 
                      else 
                          printf("客户端退出了,聊天终止!\n"); 
                      break; 
                  } 
              } 
          } 
      } 
      /*关闭聊天的套接字*/ 
      close(newfd); 
      /*是否退出服务器*/ 
      printf("服务器是否退出程序:y->是;n->否? "); 
      bzero(buf, BUFLEN); 
      fgets(buf,BUFLEN, stdin); 
      if(!strncasecmp(buf,"y",1)){ 
          printf("server 退出!\n"); 
          break; 
      } 
      } 
      /*关闭服务器的套接字*/ 
      close(sockfd); 
      return 0; 
      }
    
  • 实验截图

遇到的问题及解决方法

  • 问题:在编译多线程的代码时使用普通的gcc server.c -o server没有编译成功。
  • 解决方法:由于多线程使用到了pthread的函数库,需要手动加入,将编译命令改为gcc server.c -o server -lpthread则可以 解决这个问题。
posted on 2018-11-14 17:15  mushroom1111  阅读(137)  评论(0编辑  收藏  举报