首先是完成课堂测试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(解锁):作用于主内存中的变量,把一个处于锁定状态的变量释放出来,之后可被其它线程锁定。
来源:https://www.cnblogs.com/nhx19970709/p/7822705.html