天天看點

Linux網絡程式設計--tcp伺服器一、做為 TCP 伺服器需要具備的條件呢?關閉連接配接:close()

一、做為 TCP 伺服器需要具備的條件呢?

1.具備一個可以确知的位址( bind() ):相當于我們要明确知道移動客服的号碼,才能給他們電話;
2.讓作業系統知道是一個伺服器,而不是用戶端( listen() ):相當于移動的客服,他們主要的職責是被動接聽使用者電話,而不是主動打電話騷擾使用者;
3.等待連接配接的到來( accept() ):移動客服時刻等待着,來一個客戶接聽一個。
接收端使用 bind() 函數,來完成位址結構與socket 套接字的綁定,這樣 ip、port 就固定了,發送端即可發送資料給有明确位址( ip+port ) 的接收端。
對于 TCP 伺服器程式設計流程,有點類似于接電話過程:

1.找個可以通話的手機(socket() )

2.插上電話卡固定一個号碼( bind() )

3.職責為被動接聽,給手機設定一個鈴聲來監聽是否有來電( listen()) 

4. 有來電,确定雙方的關系後,才真正接通不挂電話( accept() ) 

5. 接聽對方的訴說( recv() ) 

6.适當給些回話( send() )

7.通信結束後,雙方說再見挂電話( close())。

int bind( int sockfd, const struct sockaddr *myaddr,socklen_t addrlen );

功能:

将本地協定位址與 sockfd 綁定,這樣 ip、port 就固定了
參數:
sockfd:socket 套接字
myaddr: 指向特定協定的位址結構指針
addrlen:該位址結構的長度
傳回值:
成功:傳回 0
失敗:-1

注意:bind隻能綁定自身的位址及端口

使用執行個體:

// 設定本地位址結構體
	struct sockaddr_in my_addr;
	bzero(&my_addr, sizeof(my_addr));			// 清空,保證最後8位元組為0    
	my_addr.sin_family = AF_INET;				// ipv4
	my_addr.sin_port   = htons(port);			// 端口
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);// ip,INADDR_ANY為通配位址其值為0
	
	// 綁定
	int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
	if( err_log != 0)
	{
		perror("binding");
		close(sockfd);		
		exit(-1);
	}
           

int listen(int sockfd, int backlog);

功能:

将套接字由主動修改為被動,使作業系統為該套接字設定一個連接配接隊列,用來記錄所有連接配接到該套接字的連接配接。更詳細說明,請看《connect()、listen()和accept()三者的關系》。
參數:
sockfd: socket監聽套接字
backlog:連接配接隊列的長度
傳回值:
成功:傳回0
失敗:其他

int accept(  int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen );

功能:

從已連接配接隊列中取出一個已經建立的連接配接,如果沒有任何連接配接可用,則進入睡眠等待(阻塞)。更詳細說明,請看《connect()、listen()和accept()三者的關系》。
參數:
sockfd: socket監聽套接字
cliaddr: 用于存放用戶端套接字位址結構
addrlen:套接字位址結構體長度的位址
傳回值:
成功:已連接配接套接字。注意:傳回的是一個已連接配接套接字,這個套接字代表目前這個連接配接
失敗:< 0
tcp_server代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>						
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>				
int main(int argc, char *argv[])
{
	unsigned short port = 8000;	// 本地端口	
	if(argc > 1)						
	{
		port = atoi(argv[1]);
	}
	//1.建立通信端點:套接字
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);   
	if(sockfd < 0)
	{
		perror("socket");
		exit(-1);
	}
	
	//設定本地位址結構體
	struct sockaddr_in my_addr;
	bzero(&my_addr, sizeof(my_addr));			// 清空,保證最後8位元組為0    
	my_addr.sin_family = AF_INET;				// ipv4
	my_addr.sin_port   = htons(port);			// 端口
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);// ip,INADDR_ANY為通配位址其值為0
	
	//2.綁定:将本地ip、端口與套接字socket相關聯起來
	int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
	if( err_log != 0)
	{
		perror("binding");
		close(sockfd);		
		exit(-1);
	}
	
	//3.監聽,監聽套接字改為被動,建立連接配接隊列
	err_log = listen(sockfd, 10); 
	if(err_log != 0)
	{
		perror("listen");
		close(sockfd);		
		exit(-1);
	}	
	
	printf("listen client @port=%d...\n",port);

	while(1)
	{	
	
		struct sockaddr_in client_addr;		   
		char cli_ip[INET_ADDRSTRLEN] = "";	   
		socklen_t cliaddr_len = sizeof(client_addr);    
		
		int connfd = 0;
		
		//4.從完成連接配接隊列中提取用戶端連接配接
		connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);       
		if(connfd < 0)
		{
			perror("accept");
			continue;
		}

		inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
		printf("----------------------------------------------\n");
		printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));
		
		char recv_buf[512] = "";
		while( recv(connfd, recv_buf, sizeof(recv_buf), 0) > 0 ) // 接收資料
		{
			printf("\nrecv data:\n");
			printf("%s\n",recv_buf);
		}
		
		close(connfd);     //關閉已連接配接套接字
		printf("client closed!\n");
	}
	
	close(sockfd);         //關閉監聽套接字
	
	return 0;
}
           

用windows的網絡調試助手作為用戶端,上面代碼為伺服器

運作結果:

Linux網絡程式設計--tcp伺服器一、做為 TCP 伺服器需要具備的條件呢?關閉連接配接:close()

關閉連接配接:close()

使用 close() 函數即可關閉套接字,關閉一個代表已連接配接套接字将導緻另一端接收到一個 0 長度的資料包,詳情請看《 TCP 四次揮手》。

做伺服器時

  • 關閉監聽套接字( socket()和listen()之後的套接字 )将導緻伺服器無法接收新的連接配接,但不會影響已經建立的連接配接;
  • 關閉 accept()傳回的已連接配接套接字将導緻它所代表的連接配接被關閉,但不會影響伺服器的監聽( socket()和listen()之後的套接字 )。
做用戶端時
關閉連接配接就是關閉連接配接,不意味着其他。
如果用戶端和伺服器已經連接配接成功的前提下,通常的情況下,先關閉用戶端,再關閉伺服器,如果是先關閉伺服器,立馬啟動伺服器是,伺服器綁定的端口不會立馬釋放(如下圖),要過 1 分鐘左右才會釋放,為什麼會這樣的呢?請看《 TCP 四次揮手》。有沒有方法讓伺服器每次啟動都能立即成功?請看《端口複用》。
Linux網絡程式設計--tcp伺服器一、做為 TCP 伺服器需要具備的條件呢?關閉連接配接:close()
源碼下載下傳: