文章目錄
- 前言
- close函數介紹
- shutdown函數介紹
前言
這裡在主要通過執行個體進行描述close函數在網絡程式設計中的使用
TCP程式設計模型中用戶端或者伺服器隻要主動通過close發起斷開連接配接的請求,則通信連接配接可以中斷。
可以通過在主程序中抓取通信端的斷開信号,比如
SIGINT
,在信号處理函數中對該通信檔案描述符進行關閉。
close函數介紹
關于close斷開連接配接的缺點:
- 會一次性将讀寫檔案描述符都關閉
- 如果多個檔案描述符指向同一個連接配接時(dup函數指派的檔案描述符/或者子程序繼承了父程序的檔案描述符),如果僅僅close其中一個檔案描述符時,隻要其他的fd還是打開狀态,那麼連接配接就不會斷開,直到所有的檔案描述符都被close之後
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <pthread.h>
typedef struct data {
char name[30];
unsigned int num;
}Data;
void print_err(char *str, int line, int err_no) {
printf("%d, %s :%s\n",line,str,strerror(err_no));
_exit(-1);
}
int cfd = -1;
//線程函數用于循環從cfd描述符中嘗試接收資料
void *receive(void *pth_arg) {
int ret = 0;
Data stu_data = {0};
while(1) {
//初始化結構體變量
bzero(&stu_data, sizeof(stu_data));
ret = recv(cfd, &stu_data, sizeof(stu_data),0);
if (-1 == ret) {
print_err("recv failed",__LINE__,errno);
}
//接收之後需要将網絡端序轉換為主機端序
printf("student number = %d student name = %s \n",ntohl(stu_data.num),stu_data.name);
}
}
/*信号處理函數,當發生SIGINT信号之後關閉通信的檔案描述符,并傳回成功*/
void sig_fun(int signo) {
if (signo == SIGINT) {
close(cfd);
_exit(0);
}
}
int main()
{
int skfd = -1, ret = -1;
skfd = socket(AF_INET, SOCK_STREAM, 0);
if ( -1 == skfd) {
print_err("socket failed",__LINE__,errno);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET; //設定tcp協定族
addr.sin_port = 6789; //設定端口号
addr.sin_addr.s_addr = inet_addr("192.168.102.169"); //設定ip位址
ret = bind(skfd, (struct sockaddr*)&addr, sizeof(addr));
if ( -1 == ret) {
print_err("bind failed",__LINE__,errno);
}
/*将套接字檔案描述符從主動轉為被動檔案描述符,然後用于被動監聽用戶端的連接配接*/
ret = listen(skfd, 3);
if ( -1 == ret ) {
print_err("listen failed", __LINE__, errno);
}
/*被動監聽用戶端發起的tcp連接配接請求,三次握手後連接配接建立成功*/
struct sockaddr_in caddr = {0};
int csize = 0;
cfd = accept(skfd, (struct sockaddr*)&caddr, &csize);
if (-1 == cfd) {
print_err("accept failed", __LINE__, errno);
}
printf("cport = %d, caddr = %s\n", ntohs(caddr.sin_port),inet_ntoa(caddr.sin_addr));
//建立子線程用于接收資料
pthread_t id;
pthread_create(&id,NULL,receive,NULL);
//建立信号處理函數
signal(SIGINT,sig_fun);
//發送資料結構體定義
Data std_data = {0};
while (1) {
printf("stu name:\n");
scanf("%s",std_data.name);
printf("stu num:\n");
scanf("%d",&std_data.num);
//對于int型的需要将主機端序轉換為網絡端序,這裡轉成long型。
std_data.num = htonl(std_data.num);
//将資料std_data強制類型轉換後發送
ret = send(cfd, (void *)&std_data,sizeof(std_data),0);
if ( -1 == ret) {
print_err("accept failed", __LINE__, errno);
}
}
return 0;
}
shutdown函數介紹
- 頭檔案
#include <sys/socket.h>
- 函數使用:
int shutdown(int sockfd, int how);
- 功能:可以按照要求關閉連接配接,且不管有多個檔案描述符指向同一個連接配接,隻要調用shutdown去操作了其中某個描述符,連接配接就會被立即斷開。
- 傳回值:成功:傳回0,失敗:傳回-1
-
參數:
a.
sockfd
通信檔案描述符,伺服器端表示accept函數傳回的連結後通信描述符
b.
how
如何斷開連接配接
SHUT_RD
隻斷開讀連接配接
SHUT_WR
隻斷開寫連接配接
讀寫連接配接都斷開SHUT_RDWR