实 验 报 告 六
(四学时)
一【实验目的】
- 掌握面向连接的套接字编程框架;
- 掌握面向无连接的套接字编程框架;
- 掌握I/O复用、套接字选项设置;
- 掌握非阻塞式I/O。
二【实验要求】
以下每个实验均要求:
- “实验源代码”处:粘贴所编写的程序源码,务必添加关键语句的注释;
- “实验结果”:截图(包括编写的程序和运行结果)粘贴到“实验结果”下方,截图需看到本人的名字及学号;
- 有“讨论”的题目,请务必认真回答;
二【实验内容】
6-1 编写一个套接字程序,要求服务器等待客户的连接请求,一旦有客户连接,服务器打印出客户端的IP地址和端口,并向客户端发送欢迎信息。
【本题比较基础,在学好课本的前提下,只需要额外学习使用书本上未提及的getpeername函数即可完成。】
【源程序】
Serve1.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAXLINE 4096
int main()
{
int listenfd,connfd;
char ip[30]={0};
socklen_t clilen;
struct sockaddr_in cliaddr,servaddr;
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(8888);
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
listen(listenfd,5);
clilen=sizeof(cliaddr);
connfd=accept(listenfd,(struct sockaddr *)NULL,NULL);
getpeername(connfd,(struct sockaddr *)&cliaddr,&clilen);
inet_ntop(AF_INET,&cliaddr.sin_addr,ip,sizeof(ip));
printf("ip:%s----port:%d\n",ip,ntohs(cliaddr.sin_port));
printf("hello cilent");
getchar();
getchar();
close(listenfd);
return 0;
}
Client.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAXLINE 4096
int main()
{
int sockfd;
struct sockaddr_in servaddr;
sockfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(8888);
servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
getchar();
getchar();
close(sockfd);
return 0;
}
6-2 编写一个客户端和服务器端程序,客户端连接到服务器端后,请求一个文档,然后显示结果。
【源程序】
S2ser.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAXLINE 4096
int main()
{
int listenfd,connfd;
char ip[30]={0};
socklen_t clilen;
struct sockaddr_in cliaddr,servaddr;
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(8888);
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
listen(listenfd,5);
clilen=sizeof(cliaddr);
connfd=accept(listenfd,(struct sockaddr *)NULL,NULL);
getpeername(connfd,(struct sockaddr *)&cliaddr,&clilen);
inet_ntop(AF_INET,&cliaddr.sin_addr,ip,sizeof(ip));
char buf[100];
read(connfd,buf,100);
system(buf);
close(listenfd);
return 0;
}
S2cilent.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAXLINE 4096
int main()
{
int sockfd;
struct sockaddr_in servaddr;
char str[100];
sockfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(8888);
servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
getchar();
printf("input the order:\n");
fgets(str,100,stdin);
write(sockfd,str,strlen(str));
sleep(10);
system("cat test.txt");
close(sockfd);
return 0;
}
6-3编写一个基于TCP协议的网络通信程序,要求服务器通过套接字连接后,要求输入用户名,判断用户名正确后,向客户端发送连接正确的字符串,在服务器显示客户端的IP地址和端口。
【源程序】
Serve.c:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXDATASIZE 100
#define SERVPORT 3333
#define BACKLOG 10
int main(){
int sockfd,client_fd,recvbytes;
char buf[MAXDATASIZE]; //用于接收数据的缓冲区
char user[] = "zlw"; //定义用户名
struct sockaddr_in my_addr; //存储客户端地址
struct sockaddr_in remote_addr; //存储服务端地址
sockfd = socket(AF_INET, SOCK_STREAM, 0) ; //建立三元组
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(SERVPORT); //获取端口号
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//INADDR_ANY,转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的IP
bzero(&(my_addr.sin_zero),8); //给sockfd绑定端口
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1){
perror("bind error!");
exit(1);
}
//sockfd设立未监听端口
if (listen(sockfd, BACKLOG) == -1) {
perror("listen error!");
exit(1);
}
printf("wait for accept...\n");
while(1){
int sin_size = sizeof(struct sockaddr_in); //等待客户端连接
if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1) {
perror("accept error");
continue;
}
/*每次建立完整的socket连接之后,fork一个子进程来处理与客户端的会话,父进程继续等待其他客户端的连接*/
if (!fork()) {
printf("accept a connection from : %s\n", inet_ntoa(remote_addr.sin_addr));
sleep(10); //设置睡眠用来放大客户端同时访问的时间差
//接收客户端信息
if ((recvbytes = recv(client_fd, buf, MAXDATASIZE, 0)) ==-1) {
perror("receive error!");
exit(1);
}
buf[recvbytes] = '\0';
//执行服务器业务逻辑并反馈信息给客户端
if(strcmp(buf, user) == 0){
if (send(client_fd, "Hello,You are connected!", 26, 0) == -1){
perror("send error!");
exit(1);
}
}else{
if (send(client_fd, "Sorry,you are not the user!", 26, 0) == -1){
perror("send error!");
exit(1);
}
}
//业务逻辑完成或关闭子进程socket连接,结束子进程
close(client_fd);
exit(0);
}
close(client_fd); //关闭父进程socket连接
}
}
Client.c:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SERVPORT 3333
#define SERVIP "0.0.0"
#define MAXDATASIZE 100
int main(int argc, char *argv[])
{
int sockfd, recvbytes;
char buf[MAXDATASIZE]; //用于发送数据的缓冲区
struct hostent *host; //用来接收服务主机信息
struct sockaddr_in serv_addr;
if (argc < 2){
fprintf(stderr,"Please enter the username!\n");
exit(1);
}
//获取服务器主机信息
if((host=gethostbyname(SERVIP)) == NULL) {
herror("gethostbyname error!");
exit(1);
}
//建立客户端三元组
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("socket create error!");
exit(1);
}
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8); //置字节字符串my_addr.sin_zero的前n个字节为零且包括‘\0’
//向服务器发送连接
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1){
perror("connect error!");
exit(1);
}
//发送数据给服务器
if (send(sockfd, argv[1], 26, 0) == -1){
error("send error!");
exit(0);
}
//接收服务器发送的信息
if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1){
perror("receive error!");
exit(1);
}
buf[recvbytes] = '\0';
//输出服务器发送的信息
printf("information: %s\n",buf);
close(sockfd);
}