实验四 Web服务器1-socket编程
实验四 Web服务器1-socket编程
目录
基于华为鲲鹏云服务器CentOS中(或Ubuntu),使用Linux Socket实现:
1. time服务器的客户端服务器,提交程序运行截图
2. echo服务器的客户端服务器,提交程序运行截图,服务器把客户端传进来的内容加入“服务器进程pid 你的学号 姓名 echo :”返回给客户端
3. 服务器部署到华为云服务器,客户端用Ubuntu虚拟机。
4. 要用多线程或者多进程实现,至少连接两个客户端。
5. 把服务器部署到试验箱。(加分项)
1.time服务器的客户端服务器,提交程序运行截图
查看IP地址:
输入代码:
csapp.c:
点击查看代码
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#define MAXLINE 100
typedef struct sockaddr SA;
#define LISTENQ 1024
#define EINTR 4
#define RIO_BUFSIZE 8192
typedef struct
{
int rio_fd;
int rio_cnt;
char *rio_bufptr;
char rio_buf[RIO_BUFSIZE];
} rio_t;
int open_listenfd(int port)
{
int listenfd, optval = 1;
struct sockaddr_in serveraddr;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval, sizeof(int)) < 0)
return -1;
bzero((char *)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if (bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
return -1;
if (listen(listenfd, LISTENQ) < 0)
return -1;
return listenfd;
}
int open_clientfd(char *hostname, int port)
{
int clientfd;
struct hostent *hp;
struct sockaddr_in serveraddr;
if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
if ((hp = gethostbyname(hostname)) == NULL)
return -2;
bzero((char *)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)hp->h_addr_list[0],
(char *)&serveraddr.sin_addr.s_addr, hp->h_length);
serveraddr.sin_port = htons(port);
if (connect(clientfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
return -1;
return clientfd;
}
ssize_t rio_writen(int fd, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
while (nleft > 0)
{
if ((nwritten = write(fd, bufp, nleft)) <= 0)
{
if ((nwritten = write(fd, bufp, nleft)) <= 0)
{
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
bufp += nwritten;
}
}
return n;
}
void rio_readinitb(rio_t *rp, int fd)
{
rp->rio_fd = fd;
rp->rio_cnt = 0;
rp->rio_bufptr = rp->rio_buf;
}
ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
{
int cnt;
while (rp->rio_cnt <= 0)
{
rp->rio_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));
if (rp->rio_cnt < 0)
{
if (errno != EINTR)
return -1;
}
else if (rp->rio_cnt == 0)
return 0;
else
rp->rio_bufptr = rp->rio_buf;
}
cnt = n;
if (rp->rio_cnt < n)
cnt = rp->rio_cnt;
memcpy(usrbuf, rp->rio_bufptr, cnt);
rp->rio_bufptr += cnt;
rp->rio_cnt -= cnt;
return cnt;
}
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
{
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++)
{
if ((rc = rio_read(rp, &c, 1)) == 1)
{
*bufp++ = c;
if (c == '\n')
break;
}
else if (rc == 0)
{
if (n == 1)
return 0;
else
break;
}
else
return -1;
}
*bufp = 0;
return n;
}
void echo(int connfd)
{
size_t n;
char buf[MAXLINE];
rio_t rio;
rio_readinitb(&rio, connfd);
while ((n = rio_readlineb(&rio, buf, MAXLINE)) != 0)
{
printf("server received %d bytes\n", n);
rio_writen(connfd, buf, n);
}
}
dataclient.c:
点击查看代码
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#define RIO_BUFSIZE 8192
typedef struct
{
int rio_fd;
int rio_cnt;
char *rio_bufptr;
char rio_buf[RIO_BUFSIZE];
} rio_t;
#define MAXLINE 200
int main(int argc, char **argv)
{
int clientfd, port;
char *host, buf[MAXLINE];
char sbuf[MAXLINE];
char rbuf[MAXLINE];
rio_t rio;
char str1[MAXLINE] = "客户端IP:";
char str2[MAXLINE] = "服务器实现者学号:20201329wh";
char str3[MAXLINE] = "当地时间:";
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);
while (1)
{
recv(clientfd, rbuf, MAXLINE, 0);
printf("%s", str1);
puts(host);
printf("%s", str2);
putchar('\n');
printf("%s", str3);
puts(rbuf);
close(clientfd);
exit(0);
}
}
dataserver.c:
点击查看代码
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define MAXLINE 200
#define RIO_BUFSIZE 8192
typedef struct
{
int rio_fd;
int rio_cnt;
char *rio_bufptr;
char rio_buf[RIO_BUFSIZE];
} rio_t;
typedef struct sockaddr SA;
typedef struct
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
} tm;
void sigchld_handler(int sig)
{
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
{
printf("child %d terminated\n", pid);
}
return;
}
int main(int argc, char **argv)
{
int listenfd, connfd, port, clientlen;
struct sockaddr_in clientaddr;
struct hostent *hp;
char *haddrp;
char sbuf[MAXLINE];
char rbuf[MAXLINE];
rio_t rio;
time_t lt;
tm *local;
char str1[MAXLINE] = "客户端IP:";
char str2[MAXLINE] = "服务器实现者学号:";
char str3[MAXLINE] = "当地时间:";
if (argc != 2)
{
fprintf(stderr, "usage:%s <port>\n", argv[0]);
exit(0);
}
port = atoi(argv[1]);
signal(SIGCHLD, sigchld_handler);
listenfd = open_listenfd(port);
while (1)
{
clientlen = sizeof(clientaddr);
connfd = accept(listenfd, (SA *)&clientaddr, &clientlen);
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);
if (fork() == 0)
{
close(listenfd);
lt = time(NULL);
local = localtime(<);
strftime(sbuf, 64, "%Y-%m-%d %H:%M:%S", local);
send(connfd, sbuf, MAXLINE, 0);
close(connfd);
exit(0);
}
close(connfd);
}
}
编译gcc csapp.c dataserver.c -o dataserver
编译gcc csapp.c dataclient.c -o dataclient
运行结果:
2.echo服务器的客户端服务器,提交程序运行截图,服务器把客户端传进来的内容加入“服务器进程pid 你的学号 姓名 echo :”返回给客户端
输入代码:
echoserver.c:
点击查看代码
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#define MAXLINE 200
#define RIO_BUFSIZE 8192
typedef struct{
int rio_fd;
int rio_cnt;
char *rio_bufptr;
char rio_buf[RIO_BUFSIZE];
}rio_t;
typedef struct sockaddr SA;
typedef struct{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
}tm;
void *thread(void *vargp);
int main(int argc,char **argv){
int listenfd,*connfdp,port;
int clientlen;
struct sockaddr_in clientaddr;
struct hostent *hp;
char *haddrp;
pthread_t tid;
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);
connfdp =malloc(sizeof(int));
*connfdp = accept(listenfd,(SA *)&clientaddr,&clientlen);
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);
pthread_create(&tid,NULL,thread,connfdp);
pthread_join(tid,NULL);
}
}
void *thread(void *vargp){
time_t lt;
tm *local;
char sbuf[MAXLINE];
char rbuf[MAXLINE];
int connfd = *((int*)vargp);
free(vargp);
pthread_detach(pthread_self());
recv(connfd,rbuf,MAXLINE,0);
printf("The massage is :%s\n",rbuf);
send(connfd,rbuf,MAXLINE,0);
close(connfd);
return NULL;
}
echoclient.c:
点击查看代码
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#define RIO_BUFSIZE 8192
typedef struct{
int rio_fd;
int rio_cnt;
char *rio_bufptr;
char rio_buf[RIO_BUFSIZE];
}rio_t;
#define MAXLINE 200
int main(int argc,char **argv){
int clientfd,port;
char *host,buf[MAXLINE];
char sbuf[MAXLINE];
char rbuf[MAXLINE];
rio_t rio;
char str1[MAXLINE]="服务器进程pid:";
char str2[MAXLINE]="服务器实现者学号姓名:20201329 魏赫";
char str3[MAXLINE]="echo:";
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);
while(1){
scanf("%[^\n]",sbuf);
send(clientfd,sbuf,MAXLINE,0);
recv(clientfd,rbuf,MAXLINE,0);
printf("%s",str1);
printf("%d\n",getpid());
printf("%s",str2);
putchar('\n');
printf("%s",str3);
puts(rbuf);
close(clientfd);
exit(0);
}
}
编译gcc csapp.c echoclient.c -pthread -o echoclient
编译gcc csapp.c echoserver.c -pthread -o echoserver
运行结果:
3.服务器部署到华为云服务器,客户端用Ubuntu虚拟机。
打开openeuler虚拟机,查看IP地址为192.168.87.138
:
运行结果:
4.要用多线程或者多进程实现,至少连接两个客户端。
输入代码:
myserver.c:
点击查看代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<pthread.h>
void* communication(void* arg);
int main()
{
int sockfd=socket(PF_INET,SOCK_STREAM,0);
assert(-1!=sockfd);
struct sockaddr_in ser,cli;
ser.sin_family=AF_INET;
ser.sin_port=htons(6000);
ser.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr*)&ser,sizeof(ser));
assert(-1!=res);
listen(sockfd,5);
while(1)
{
int len=sizeof(cli);
int c=accept(sockfd,(struct sockaddr*)&cli,&len);
if(c<0)
{
printf("link error\n");
continue;
}
pthread_t id;
int n=pthread_create(&id,NULL,communication,(void*)c);
assert(n==0);
}
close(sockfd);
}
void* communication(void* arg)
{
while(1)
{
char buff[128]={0};
int c=(int)arg;
int n=recv(c,buff,127,0);
if(n<=0)
{
close(c);
printf("%d client over\n",c);
break;
}
printf("%d:%s\n",c,buff);
send(c,"OK",2,0);
}
}
myclient.c:
点击查看代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{
int sockfd = socket(PF_INET,SOCK_STREAM,0);
assert(-1!=sockfd);
struct sockaddr_in ser,cli;
memset(&ser,0,sizeof(ser));
ser.sin_family=AF_INET;
ser.sin_port=htons(6000);
ser.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=connect(sockfd,(struct sockaddr*)&ser,sizeof(ser));
assert(res!=-1);
while(1)
{
printf("Please input:");
fflush(stdout);
char buff[128]={0};
fgets(buff,127,stdin);
buff[strlen(buff)-1]=0;
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);
memset(buff,0,sizeof(buff));
recv(sockfd,buff,127,0);
printf("%s\n",buff);
}
close(sockfd);
}
运行结果:
服务器端:
客户端1:
客户端2:
客户端3: