首先是完成课堂测试3

基于socket 使用教材的csapp.h,和csapp.c实现daytime(13)服务端(端口我们是用的是13+后三位学号)和客户端,以下是服务器相应格式。

首先我们要写的是客户端的代码:

#include    "unp.h"
  
  int
  main(int argc, char **argv)
  {
       int                 sockfd, n;
      char                recvline[MAXLINE + 1];
      struct sockaddr_in  servaddr;
  
    if (argc != 2)
        err_quit("usage: a.out <IPaddress>");
 
     if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
          err_sys("socket error");
 
     bzero(&servaddr, sizeof(servaddr));
     servaddr.sin_family = AF_INET;
     servaddr.sin_port   = htons(13);    /* daytime server */
      if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
          err_quit("inet_pton error for %s", argv[1]);
 
      if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
          err_sys("connect error");
 
      while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
         recvline[n] = 0;    /* null terminate */
         if (fputs(recvline, stdout) == EOF)
             err_sys("fputs error");
    }                                                                                                               
    if (n < 0)
         err_sys("read error");
         
     exit(0);
 }

客户端的程序主要是向服务器发送连接请求,建立连接之后,然后读取从服务器传回来的数据。

接下来是服务器的代码

  #include    "unp.h"                                                                                               
   #include    <time.h>
  
  int
   main(int argc, char **argv)
  {
      int                 listenfd, connfd;
      struct sockaddr_in  servaddr;
       char                buff[MAXLINE];
     time_t              ticks;
 
      listenfd = Socket(AF_INET, SOCK_STREAM, 0);
 
      bzero(&servaddr, sizeof(servaddr));
      servaddr.sin_family      = AF_INET;
     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
     servaddr.sin_port        = htons(13);   /* daytime server */
     Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
 
      Listen(listenfd, LISTENQ);
 
     for ( ; ; ) {
         connfd = Accept(listenfd, (SA *) NULL, NULL);
         ticks = time(NULL);
          snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
          snprint(buff,sizeof(buff),"客户端Ip:127.0.1\n服务器实现者学号:20155309\n当前时间:%.24s\r\n",crime(&ticks));
         Write(connfd, buff, strlen(buff));
         Close(connfd);
      }
  }

问题及解决

代码不能够运行?

我仔细的检查了客户端与服务器的代码之后,发现

切换到root用户下执行:

# ./configure     //在unpv13e当前目录下执行configure
# cd lib       //然后进入 lib目录,make一下编译环境
# make

前期准备工作完成了

然后在 ./intro/目录下有原始版本的 daytimetcpcli.c(client源码) 以及daytimetcpsrv.c (server端源码);
如果没有两台服务器的话,那么我们就在同一台服务器下面开两个进程(终端),其中一个作为server:

# cd intro/
# make daytimetcpsrv
# ./daytimetcpsrv           // 编译完之后,运行,server端就开始监听了。

一个进程作为client:

# cd intro/
# make daytimetcpcli
# ./daytimetcpcli 127.0.0.1      //因为是在同一台主机上测试,所ip地址取127也可以取本地实际的地址,因为我的是在虚拟机下,所以192的ip也没什么意义。

然后就可以看到客户端以及将服务器端的server拿回了。至此一个简单而典型的socket程序就部署成功了。

这样我们就可以运行代码了。

课下关于多线程的作业:

echoserveri.c :

/* 
 * echoserveri.c - An iterative echo server 
 */ 
/* $begin echoserverimain */
#include "csapp.h"

void echo(int connfd);

int main(int argc, char **argv) 
{
    int listenfd, connfd, port, clientlen;
    struct sockaddr_in clientaddr;
    struct hostent *hp;
    char *haddrp;
    if (argc != 2) {
    fprintf(stderr, "usage: %s <port>\n", argv[0]);
    exit(0);
    }
    port = atoi(argv[1]);

    listenfd = Open_listenfd(port);
    while (1) {
    clientlen = sizeof(clientaddr);
    connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);

    /* determine the domain name and IP address of the client */
    hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, 
               sizeof(clientaddr.sin_addr.s_addr), AF_INET);
    haddrp = inet_ntoa(clientaddr.sin_addr);
    printf("server connected to %s (%s)\n", hp->h_name, haddrp);

    echo(connfd);
    Close(connfd);
    }
    exit(0);
}
/* $end echoserverimain */




echoclient.c:

/*
 * echoclient.c - An echo client
 */
/* $begin echoclientmain */
#include "csapp.h"

int main(int argc, char **argv) 
{
    int clientfd, port;
    char *host, buf[MAXLINE];
    rio_t rio;

    if (argc != 3) {
    fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);
    exit(0);
    }
    host = argv[1];
    port = atoi(argv[2]);

    clientfd = Open_clientfd(host, port);
    Rio_readinitb(&rio, clientfd);

    while (Fgets(buf, MAXLINE, stdin) != NULL) {
    Rio_writen(clientfd, buf, strlen(buf));
    Rio_readlineb(&rio, buf, MAXLINE);
    Fputs(buf, stdout);
    }
    Close(clientfd);
    exit(0);
}
/* $end echoclientmain */

修改后的代码为:

/*
 * echoclient.c - An echo client
 */
/* $begin echoclientmain */
#include "csapp.h"

int main(int argc, char **argv) 
{
    int clientfd, port;
    char *host, buf[MAXLINE];
    rio_t rio;

    if (argc != 3) {
    fprintf(stderr, "usage: %s <host> <port>\n", argv[0]);
    exit(0);
    }
    host = argv[1];
    port = atoi(argv[2]);

    clientfd = Open_clientfd(host, port);
    Rio_readinitb(&rio, clientfd);

    while (Fgets(buf, MAXLINE, stdin) != NULL) {
    
    time_t t;
    struct tm * lt;
    size_t n; 
    printf("\n客户端IP:127.0.0.1\n");
    printf("服务器实现者学号:20155309\n");
    
    time (&t);
    lt = localtime (&t);
    printf ("当前时间为:%d/%d/%d %d:%d:%d\n",lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
    Rio_writen(clientfd, buf, strlen(buf));
    Rio_readlineb(&rio, buf, MAXLINE);
    Fputs(buf, stdout);
    }
    Close(clientfd); //line:netp:echoclient:close
    exit(0);
}
/* $end echoclientmain */

关于多线程的思考

Lock(锁定):作用于主内存中的变量,把一个变量标识为一条线程独占的状态。

Read(读取):作用于主内存中的变量,把一个变量的值从主内存传输到线程的工作内存中。

Load(加载):作用于工作内存中的变量,把read操作从主内存中得到的变量的值放入工作内存的变量副本中。

Use(使用):作用于工作内存中的变量,把工作内存中一个变量的值传递给执行引擎。

Assign(赋值):作用于工作内存中的变量,把一个从执行引擎接收到的值赋值给工作内存中的变量。

Store(存储):作用于工作内存中的变量,把工作内存中的一个变量的值传送到主内存中。

Write(写入):作用于主内存中的变量,把store操作从工作内存中得到的变量的值放入主内存的变量中。

Unlock(解锁):作用于主内存中的变量,把一个处于锁定状态的变量释放出来,之后可被其它线程锁定。