1. 程式人生 > >套接字socket--概念和例項

套接字socket--概念和例項

套接字 socket

 

套接字概念

套接字是一種程序間通訊的方法,不同於以往介紹的的程序通訊方法的是,它並不侷限於同一臺計算機的資源,例如共享內容或者訊息佇列。

一臺機器上的程序可以使用套接字與另一臺機器上的程序通訊。因此客戶與伺服器可以分散到網路中。

同一臺機器的程序間也可以用套接字通訊。

 

套接字的工作過程(伺服器端)

首先,伺服器應用程式通過socket系統呼叫建立一個套接字,它是系統分配給該伺服器程序的類似檔案描述符的資源,不能與其他程序共享。

其次,伺服器程序使用bind系統呼叫個套接字命名。

接下來,伺服器程序開始等待客戶連線到這個命名套接字,呼叫listen建立一個等待佇列,以使存放來自客戶的進入連線。

最後,伺服器通過accept系統呼叫來接受客戶的連線。此時,會產生一個與原有的命名套接字不同的新套接字,它僅用於與這個特定的客戶端,而命名套接字則被保留下來繼續處理來自其他客戶的連線。

 

套接字的工作工程(客戶端)

呼叫socket建立一個未命名套接字,將伺服器的命名套接字作為一個地址來呼叫connect與伺服器建立連線。

一旦建立了連線,就可以像使用底層檔案描述符那樣來用套接字進行雙向的資料通訊。

 

套接字的屬性

套接字的特性由三個屬性決定:

域(domain):指定套接字通訊中使用的網路介質,包括地址格式。

  • AF_INET,即網際網路絡,基於IP協議,並且每個對應一個埠號,套接字地址由IP地址+埠號決定

型別(type)

  • 流套接字:由型別SOCK_STREAM指定,基於TCP/IP實現,提供一個有序、可靠、雙向位元組流的連線,傳送的資料不會丟失、亂序、重複。大的訊息會被分塊、傳輸、重組,很像一個檔案流。
  • 資料報套接字:由SOCK_DGRAM指定,基於UDP/IP協議,不建立和維持可靠連線,開銷小,伺服器崩潰不需要客戶端重啟,因為基於資料報的伺服器不保留連線資訊

協議(protocol)

 

 

套接字舉例

客戶端程式:建立一個未命名的套接字,然後把它連線到伺服器套接字server_socket上,向伺服器寫一個字元,再讀回經伺服器處理後的一個字元。

伺服器端程式:首先建立一個伺服器套接字,繫結一個名字,然後建立一個監聽佇列,接收來自客戶程式的連線。

client1.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <unistd.h>

int main()
{
	int sockfd;
	int len;
	struct sockaddr_un address;
	int result;
	char ch = 'A';
	sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
	//根據伺服器的情況設定連續地址
	address.sun_family = AF_UNIX;
	strcpy(address.sun_path, "server_socket");
	len = sizeof(address);

	result = connect(sockfd, (struct sockaddr *)&address, len);
	if (result == -1)
	{
		perror("oops:client1");
		exit(1);
	}
	write(sockfd, &ch, 1);
	read(sockfd, &ch, 1);
	printf("char from server = %c\n", ch);
	close(sockfd);
	exit(0);
}

server1.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>

int main()
{
	int server_sockfd, client_sockfd;//定義套接字識別符號
	int server_len, client_len;//地址長度
	struct sockaddr_un server_address;
	struct sockaddr_un client_address;
	unlink("server_socket");//如果當前目錄有叫做server_socket的檔案,則刪掉
	server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);//採用位元組流方式,預設協議
	server_address.sun_family = AF_UNIX;
	strcpy(server_address.sun_path, "server_socket");
	server_len = sizeof(server_address);
	bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
	listen(server_sockfd, 5);//建立長度為5的監聽佇列
	while(1)//等待客戶端連線的到來
	{
		char ch;
		printf("server waiting\n");
		client_len = sizeof(client_address);//獲取客戶端的地址長度
		//伺服器程序阻塞自身,知道有客戶端請求建立連線,此時生成一個新的套接字,並返回新套接子的描述符,用此新套接字與客戶進行通訊
		client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);
		read(client_sockfd, &ch, 1);
		ch++;
		write(client_sockfd, &ch, 1);
		close(client_sockfd);
	} 
}