TCP/IP网络编程 (七):优雅地断开套接字连接

基于TCP的半关闭

单方面断开连接带来的问题

                                    

调用close函数断开连接,意味着完全断开连接,不仅无法传输数据,而且也不能接收数据。

 

套接字和流(Stream)

两台主机通过套接字建立连接后进入可交换数据的状态。把建立套接字后可交换数据的状态看作一种流。

为了实现双向通信,套接字生成的两个流。

 

针对优雅断开的shutdown函数

shutdown函数关闭其中一个流。

 

调用上述函数时,第二个参数决定断开连接的方式:

-SHUT_RD:断开输入流

-SHUT_WR:断开输出流

-SHUT_RDWR:同时断开I/O流

 

 

 

基于半关闭的文件传输程序

“一旦客户连接到服务器端,服务器端将约定的文件传给客户端,客户端收到后发送字符串  ‘Thank you’ 给服务器端。

                                                          

 

 

服务端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUF_SIZE 30
void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

int main(int argc, char *argv[])
{
	int serv_sd, clnt_sd;
	FILE *fp;
	char buf[BUF_SIZE];
	int read_cnt;

	struct sockaddr_in serv_adr, clnt_adr;
	socklen_t clnt_adr_sz;

	if (argc != 2)
	{
		printf("Usage: %s <port> \n",argv[0]);
		exit(1);
	}

	fp = fopen("file_server.c","rb");
	serv_sd = 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]));

	bind(serv_sd,(struct sockaddr*) &serv_adr,sizeof(serv_adr));
	listen(serv_sd,5);

	clnt_adr_sz = sizeof(clnt_adr);
	clnt_sd = accept(serv_sd,(struct sockaddr*) &clnt_adr, &clnt_adr_sz);

	while(1)
	{
		read_cnt = fread((void*)buf,1,BUF_SIZE,fp);			//从文件描述符fp指向的文件中读数据到buf缓冲区
		if (read_cnt < BUF_SIZE)
		{
			write(clnt_sd,buf,read_cnt);
			break;
		}
		write(clnt_sd,buf,BUF_SIZE);
	}

	shutdown(clnt_sd,SHUT_WR);						//发送文件后针对输出流进行半关闭。
	read(clnt_sd,buf,BUF_SIZE);						//只关闭了输出流,依旧可以通过输入流接收数据。
	printf("Message from client: %s \n",buf);
	
	fclose(fp);
	close(clnt_sd); close(serv_sd);
	return 0;
}

客户端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUF_SIZE 30
void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

int main(int argc, char *argv[])
{
	int sd;
	FILE *fp;

	char buf[BUF_SIZE];
	int read_cnt;
	struct sockaddr_in serv_adr;

	if (argc != 3)
	{
		printf("Usage: %s <port> \n",argv[0]);
		exit(1);
	}

	fp = fopen("receive.dat","wb");						//创建新文件保存服务器端传输的文件数据
	sd = 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 = inet_addr(argv[1]);
	serv_adr.sin_port = htons(atoi(argv[2]));

	connect(sd,(struct sockaddr*) &serv_adr,sizeof(serv_adr));

	while ((read_cnt = read(sd,buf,BUF_SIZE)) != 0)
		fwrite((void*)buf,1,read_cnt,fp);				//将接收的数据写入到fp指向的文件receive.dat中

	puts("Receive file data");
	write(sd,"Thank you",10);
	fclose(fp);
	close(sd);
	return 0;
}



猜你喜欢

转载自blog.csdn.net/amoscykl/article/details/80220309