基于TCP的半關(guān)閉
在前面的章節(jié)中,我們都是通過close或者closesocket來斷開套接字連接的,但是調(diào)用這兩個函數(shù)導(dǎo)致我們套接字完全斷開,套接字將無法接受數(shù)據(jù),并且也只能傳輸完最后余留在緩沖區(qū)的數(shù)據(jù)內(nèi)容。此時"只關(guān)閉一部分?jǐn)?shù)據(jù)交換中使用的流"的方法應(yīng)運而生。
針對優(yōu)雅斷開的shutdown函數(shù)
#include<sys/socket.h>
int shutdown(int sock,int howto);//成功時返回0,失敗時返回-1
sock //需要半斷開的文件描述符、
howto //進行半斷開的方式
此函數(shù)的第二個參數(shù)可能是下面之一:
1.SHUT_RD//斷開輸入流
2.SHUT_WR//斷開輸出流
3.SHUT_RDWR//同時斷開IO流
為何需要半關(guān)閉
試想一個場景,在客戶端和服務(wù)端建立連接后,服務(wù)端向客戶端傳遞文件,當(dāng)服務(wù)端傳遞完文件后,客戶端需要發(fā)送一個"Thank you"給服務(wù)端。這里就有一個問題,客戶端該何時知道它應(yīng)該發(fā)送“Thank you”給服務(wù)端。如果服務(wù)端通過close關(guān)閉套接字發(fā)EOF給客戶端的話,服務(wù)端將再也無法接受“Thank you”。因此如果服務(wù)端只用關(guān)閉它的輸出流,并且傳遞EOF給客戶端的話就能夠解決這個問題。shutdown函數(shù)的半關(guān)閉可以同時做到上述的兩個需求。
基于半關(guān)閉的文件傳輸程序
下面介紹服務(wù)器的代碼:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#defind BUF_SIZE 30;
void error_handling(char*message);
int main(int argc,char *argv[]){
int serv_sd,clnt_sd;
FILE *fp;
char buf[BUF_SIZE];
int read_cnt;
struct sockaddr_in serv_addr,clnt_addr;
socklen_t clnt_addr_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_addr,0,sizeof(serv_addr));
serv_addr.sin_familiy=AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(atoi(argv[1]));
bind(serv_sd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
listen(serv_sd,5);
clnt_addr_sz=sizeof(clnt_addr);
clnt_sd=accept(serv_ad,(struct sockaddr*)&clnt_addr,&clnt_addr_sz);
while(1){
read_cnt=fread((void*)buf,1,BUF_SIZE,fp);
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;
}
void error_handling(char *message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
下面介紹客戶端代碼:
#include<"與服務(wù)器頭文件聲明一致,故省略">
#defind BUF_SIZE 30
void error_handling(char *message);
int main(int argc,char*argv[]){
int sd;
FILE *fp;
char buf[BUF_SIZE];
int read_cnt;
struct sockaddr_in serv_addr;
if(argc!=3){
printf("Usage: %s <IP> <port>\n",argv[0]);
exit(1);
}
fp=fopen("receive.dat","wb");
sd=socket(PF_INET,SOCK_STREAM,0);
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
serv_addr.sin_port=htons(atoi(argv[2]));
connect(sd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
while((read_cnt=read(sd,buf,BUF_SIZE))!=0)
fwrite((void*)buf,1,read_cnt,fp);
puts("Reveived file data");
write(sd,"Thank you",10);
fclose(fp);
close(sd);
return 0;
}
void error_handling(char*message){
//與服務(wù)器的內(nèi)容一致
}
基于Windows的實現(xiàn)
Windows平臺同樣通過調(diào)用shutdown函數(shù)完成半關(guān)閉,只是想起傳遞的參數(shù)名略有不同。
#include<winsock2.h>
int shutdown(SOCKET sock,int howto);//成功返回0.失敗返回SOCKET_ERROR;
sock //要斷開的套接字句柄
howto //斷開方式的信息
上述函數(shù)的第二個參數(shù)的可能值及其含義如下:
1.SD_RECEIVE:斷開輸入流
2.SD_SEND:斷開輸出流
3.SD_BOTH:斷開IO流文章來源:http://www.zghlxwxcb.cn/news/detail-582635.html
雖然這些常量名不同于Linux中的名稱,但是其內(nèi)部的值完全相同。文章來源地址http://www.zghlxwxcb.cn/news/detail-582635.html
到了這里,關(guān)于TCP/IP 網(wǎng)絡(luò)編程 第七章:優(yōu)雅地斷開套接字連接的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!