《TCP/IP网络编程》课后练习第十五-十八章(自己写的,非标准答案)

第十五章

(1)

标准I/O函数具有良好的移植性,不仅是I/O函数,所有标准函数具有良好的移植性,为了支持所有操作系统,这些函数都是按照ANSI C标准定义的

标准I/O函数可以利用缓冲提高性能,使用标准I/O函数时会得到额外的缓冲支持,需要传输的数据越多,有无缓冲带来的性能差异越大

(2)

使用标准I/O函数传输数据时,经过2个缓冲,通过fputs函数传输字符串时,首先将数据传递到标准I/O函数的缓冲,然后数据将移动到套接字输出缓冲,最后将字符串发送到对方主机

第十六章

(1)

abcd

(2)

第十七章

(1)

调用select函数后常见的针对所有文件描述符的循环语句

每次调用select函数时都需要向该函数传递监视对象信息

(2)

套接字是由操作系统管理的,监视套接字变化的函数必须要借助于操作系统才能完成功能

(3)

select函数每次调用时都向操作系统传递传递监视对象信息,而epoll仅向操作系统传递1次监视对象,监视范围或内容发生变化时只通知发生变化的事项,因为每种操作系统支持的程度和方式存在差异

(4)

服务器端接入者少,程序应具有兼容性

(5)

条件触发方式中,只要输入缓冲有数据就会一直通知该事件,边缘触发中仅在输入缓冲收到数据时注册1次该事件

(6)

因为边缘触发只注册一次事件,条件触发注册多次事件,如果强行分离数据的接收和处理时间点,服务器端不能承受,这种分离给服务器端带来了巨大的灵活性

(7)

chat_EPLTserv.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#define BUF_SIZE 4
#define EPOLL_SIZE 50
#define MAX_CLNT 256
void error_handling(char *buf);

int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;
	struct sockaddr_in serv_adr, clnt_adr;
	socklen_t adr_sz;
	int str_len, i;
	char buf[BUF_SIZE];
	
	struct epoll_event *ep_events;
	struct epoll_event event;
	int epfd, event_cnt;
	
	int clnt_cnt = 0;
	int clnt_socks[MAX_CLNT];

	if(argc != 2){
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}
	
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	memset(&serv_adr, 0, sizeof(serv_adr));
	serv_adr.sin_family = AF_INET;
	serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_adr.sin_port = htons(atoi(argv[1]));
	
	if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
		error_handling("bind() error");
	if(listen(serv_sock, 5) == -1)
		error_handling("listen() error");
		
	epfd = epoll_create(EPOLL_SIZE);
	ep_events = malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
	
	event.events = EPOLLIN;
	event.data.fd = serv_sock;
	epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);
	
	while(1)
	{
		event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
		if(event_cnt == -1)
		{
			puts("epoll_wait() error");
			break;
		}
		
		puts("return epoll_wait");
		for(i = 0; i < event_cnt; ++i)
		{
			if(ep_events[i].data.fd == serv_sock)
			{
				adr_sz = sizeof(clnt_adr);
				clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
				event.events = EPOLLIN;
				event.data.fd = clnt_sock;
				epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);
				
				clnt_socks[clnt_cnt++] = clnt_sock;
				
				printf("connected client: %d \n", clnt_sock);
			}
			else
			{
				str_len = read(ep_events[i].data.fd, buf, BUF_SIZE);
				if(str_len == 0)
				{
					epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
					for(int j = 0; j < clnt_cnt; ++j){
						if(ep_events[i].data.fd == clnt_socks[j]){
							while(j < clnt_cnt - 1)
							{
								clnt_socks[j] = clnt_socks[j + 1];
								++j;
							}
							break;
						}
					}
					--clnt_cnt;
					close(ep_events[i].data.fd);
					printf("closed client: %d \n", ep_events[i].data.fd);
				}
				else
				{
					for(int i = 0; i < clnt_cnt; ++i)
						write(clnt_socks[i], buf, str_len);
				}
			}
		}
	}
	close(serv_sock);
	close(epfd);
	return 0;
}

void error_handling(char *buf)
{
	fputs(buf, stderr);
	fputc('\n', stderr);
	exit(1);
}

chat_EPETserv.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
#define BUF_SIZE 4
#define EPOLL_SIZE 50
#define MAX_CLNT 256
void setnonblockingmode(int fd);
void error_handling(char *buf);

int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;
	struct sockaddr_in serv_adr, clnt_adr;
	socklen_t adr_sz;
	int str_len, i;
	char buf[BUF_SIZE];
	
	struct epoll_event *ep_events;
	struct epoll_event event;
	int epfd, event_cnt;
	
	int clnt_cnt = 0;
	int clnt_socks[MAX_CLNT];
	
	if(argc != 2){
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}
	
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	memset(&serv_adr, 0, sizeof(serv_adr));
	serv_adr.sin_family = AF_INET;
	serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_adr.sin_port = htons(atoi(argv[1]));
	if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
		error_handling("bind() error");
	if(listen(serv_sock, 5) == -1)
		error_handling("listen() error");
		
	epfd = epoll_create(EPOLL_SIZE);
	ep_events = malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
	
	setnonblockingmode(serv_sock);
	event.events = EPOLLIN;
	event.data.fd = serv_sock;
	epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);
	
	while(1)
	{
		event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
		if(event_cnt == -1)
		{
			puts("epoll_wait() error");
			break;
		}
		
		puts("return epoll_wait");
		for(i = 0; i < event_cnt; ++i)
		{
			if(ep_events[i].data.fd == serv_sock)
			{
				adr_sz = sizeof(clnt_adr);
				clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
				setnonblockingmode(clnt_sock);
				event.events = EPOLLIN | EPOLLET;
				event.data.fd = clnt_sock;
				epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);
				
				clnt_socks[clnt_cnt++] = clnt_sock;
				
				printf("connected client: %d \n", clnt_sock);
			}
			else
			{
				while(1)
				{
					str_len = read(ep_events[i].data.fd, buf, BUF_SIZE);
					if(str_len == 0)
					{
						epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
						
						for(int j = 0; j < clnt_cnt; ++j){
							if(ep_events[i].data.fd == clnt_socks[j]){
								while(j < clnt_cnt - 1)
								{
									clnt_socks[j] = clnt_socks[j + 1];
									++j;
								}
								break;
							}
						}
						--clnt_cnt;
						
						close(ep_events[i].data.fd);
						printf("closed client: %d \n", ep_events[i].data.fd);
						break;
					}
					else if(str_len < 0)
					{
						if(errno == EAGAIN)
							break;
					}
					else
					{
						for(int i = 0; i < clnt_cnt; ++i)
							write(clnt_socks[i], buf, str_len);
					}
				}
			}
		}
	}
	close(serv_sock);
	close(epfd);
	return 0;
}

void setnonblockingmode(int fd)
{
	int flag = fcntl(fd, F_GETFL, 0);
	fcntl(fd, F_SETFL, flag | O_NONBLOCK);
}

void error_handling(char *buf)
{
	fputs(buf, stderr);
	fputc('\n', stderr);
	exit(1);
}

第十八章

(1)

系统将CPU时间分成多个微小的块后分配给多个进程

运行程序前需要将相应进程信息读入内存,如果运行进程A后需要紧接着运行进程B,就应该将进程A相关信息移出内存,并读入进程B相关信息,这就是上下文切换

(2)

同一进程的线程间共享数据区和堆,上下文切换时不需要切换数据区和堆,可以利用数据区和堆交换数据

(3)

进程在操作系统构成单独执行流的单位

线程在进程构成单独执行流的单位

(4)

bcd

(5)

d

(6)

调用pthread_join函数或调用pthread_detach函数

(7)

echo_multithreadserv.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#define BUF_SIZE 100
#define MAX_CLNT 256

void *handle_clnt(void *arg);
void error_handling(char *buf);

int clnt_cnt = 0;
int clnt_socks[MAX_CLNT];
char buf[BUF_SIZE];

pthread_mutex_t mutx;
pthread_mutex_t mutx_2;

int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;
	struct sockaddr_in serv_adr, clnt_adr;
	int clnt_adr_sz;
	pthread_t t_id;
	if(argc != 2){
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}
	
	pthread_mutex_init(&mutx, NULL);
	pthread_mutex_init(&mutx_2, NULL);
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	
	memset(&serv_adr, 0, sizeof(serv_adr));
	serv_adr.sin_family = AF_INET;
	serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_adr.sin_port = htons(atoi(argv[1]));
	
	if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
		error_handling("bind() error");
	if(listen(serv_sock, 5) == -1)
		error_handling("listen() error");
		
	while(1){
		clnt_adr_sz = sizeof(clnt_adr);
		clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
		
		pthread_mutex_lock(&mutx);
		clnt_socks[clnt_cnt++] = clnt_sock;
		pthread_mutex_unlock(&mutx);
		
		pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);
		pthread_detach(t_id);
		printf("Connected client IP: %s \n", inet_ntoa(clnt_adr.sin_addr));
	}
	close(serv_sock);
	return 0;
}

void *handle_clnt(void *arg){
	int clnt_sock = *((int*)arg);
	int str_len = 0, i;
	char msg[BUF_SIZE];
	
	while(1)
	{
		pthread_mutex_lock(&mutx_2);
		str_len=read(clnt_sock, msg, sizeof(msg));
		pthread_mutex_unlock(&mutx_2);
		if(str_len == 0)
			break;
		pthread_mutex_lock(&mutx_2);
		write(clnt_sock, msg, str_len);
		pthread_mutex_unlock(&mutx_2);
		sleep(1);
	}
		
	pthread_mutex_lock(&mutx);
	for(i = 0; i < clnt_cnt; ++i){
		if(clnt_sock == clnt_socks[i]){
			while(i < clnt_cnt - 1)
			{
				clnt_socks[i] = clnt_socks[i + 1];
				++i;
			}
			break;
		}
	}
	--clnt_cnt;
	
	pthread_mutex_unlock(&mutx);
	close(clnt_sock);
	return NULL;
}

void error_handling(char *buf)
{
	fputs(buf, stderr);
	fputc('\n', stderr);
	exit(1);
}

(8)

不同步多线程访问临界区会产生问题,同步的话由于read阻塞,同一时间只有一个客户端线程的消息能够读取

  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值