1. 程式人生 > >網路程式設計之基於TCP 的Sockets程式設計

網路程式設計之基於TCP 的Sockets程式設計

百度百科言:多個TCP連線或多個應用程序程序可能需要通過同一個 TCP協議埠傳輸資料。為了區別不同的應用程式程序和連線,許多計算機作業系統為應用程式與TCP/IP協議互動提供了稱為套接字(Socket)的介面。簡單的說套接字就是一種支援TCP/IP的網路通訊的基本操作單元,可以看做是不同主機之間的程序進行雙向通訊的端面點,也就是通訊的兩方的一種約定,用套接字中的相關函式來完成通訊過程。常用的TCP/IP協議套接字有三種,分別是:

流套接字(SOCK_STREAM):   流套接字用於提供面向連線、可靠的資料傳輸服務。該服務將保證資料能夠實現無差錯、無重複傳送,並按順序接收。流套接字之所以能夠實現可靠的資料服務,原因在於其使用了傳輸控制協議,即

TCPThe Transmission Control Protocol)協議。   

資料報套接字(SOCK_DGRAM):資料報套接字提供了一種無連線的服務。該服務並不能保證資料傳輸的可靠性,資料有可能在傳輸過程中丟失或出現數據重複,且無法保證順序地接收到資料。資料報套接字使用UDPUser Datagram Protocol)協議進行資料的傳輸。由於資料包套接字不能保證資料傳輸的可靠性,對於有可能出現的資料丟失情況,需要在程式中做相應的處理。   

原始套接字(SOCK_RAW):原始套接字與標準套接字(標準套接字指的是前面介紹的流套接字和資料報套接字)的區別在於:原始套接字可以讀寫核心沒有處理的

IP資料包,而流套接字只能讀取TCP協議的資料,資料報套接字只能讀取UDP協議的資料。因此,如果要訪問其他協議傳送資料必須使用原始套接字。

我們如果想要用套接字實現網路通訊,那就應該至少需要一對,一個在伺服器端(ServerSocket),一個則執行在客戶端(ClientSocket)。而套接字的連線建立過程由伺服器監聽、客戶端請求和連線確認三個步驟完成。使用套接字進行資料處理有同步模式和非同步模式,兩者的不同點就在於前者只適合用於資料處理不太多的場合,而後者比較適合於進行大量資料處理的場合。

windows網路程式設計均是由windows套接字實現,經常用到的是MFC類庫中的CSocket

類。使用該類的基本流程如下:

建立套接字———>繫結地址資訊———>連線伺服器———>資料交換

———>關閉套接字物件。

下面用VC6實現同步模式下的一個簡單例子:

首先建立的是伺服器端:

#include <winsock2.h>	//包含標頭檔案
#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"WS2_32.lib");//顯示連線套接字型檔
int main()
{
	WSADATA data;//定義結構體物件
	WORD w=MAKEWORD(2,0);//定義版本號碼
	char sztext[]="歡迎你\r\n";//定義並初始化傳送到客戶端的字元陣列
	::WSAStartup(w,&data);//初始化套接字型檔
	SOCKET s,s1;//定義連線套接字和資料收發套接字控制代碼
	s=::socket(AF_INET,SOCK_STREAM,0);//建立TCP套接字
	sockaddr_in addr,addr2;//定義套接字地址結構
	int n=sizeof(addr2);//獲取套接字地址結構大小
	addr.sin_family=AF_INET;//初始化地址結構
	addr.sin_port=htons(75);
	addr.sin_addr.S_un.S_addr=INADDR_ANY;
	::bind(s,(sockaddr*)&addr,sizeof(addr));//繫結套接字
	::listen(s,5);//監聽套接字
	printf("伺服器已經啟動...........\r\n");
	while(true)
	{
		s1=::accept(s,(sockaddr*)&addr2,&n);//接受連線請求
		if(s1!=NULL)
		{
			printf("%s已經連線上...........\r\n",inet_ntoa(addr2.sin_addr));
			::send(s1,sztext,sizeof(sztext),0);//向客戶端放送字元陣列
		}
		::closesocket(s);//關閉套接字控制代碼
		::closesocket(s1);
		::WSACleanup();//釋放套接字
		if(getchar())//如果有輸入則關閉程式
		{
			return 0;//正常結束程式
		}
		else
		{
			::Sleep(100);//應用睡眠0.1秒
		}
	}
	return 0;
}

然後建立客戶端:

#include <winsock2.h>	//包含標頭檔案
#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"WS2_32.lib");//顯示連線套接字型檔
int main()
{
	WSADATA data;//定義結構體物件
	WORD w=MAKEWORD(2,0);//定義版本號碼
	::WSAStartup(w,&data);//初始化套接字型檔
	SOCKET s;//定義連線套接字和資料收發套接字控制代碼
	char sztext[10]={0};
	s=::socket(AF_INET,SOCK_STREAM,0);//建立TCP套接字
	sockaddr_in addr,addr2;//定義套接字地址結構
	int n=sizeof(addr2);//獲取套接字地址結構大小
	addr.sin_family=AF_INET;//初始化地址結構
	addr.sin_port=htons(75);
	addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
	printf("客戶端已經啟動....\r\n");
	::connect(s,(sockaddr*)&addr,sizeof(addr));
	::recv(s,sztext,sizeof(sztext),0);
	printf("%s\r\n",sztext);
	::closesocket(s);
	::WSACleanup();
	if(getchar())
	{
		return 0;
	}
	else
	{
		::Sleep(100);
	}
}

執行伺服器端和客戶端程式,可以知道伺服器和客戶端已經啟動,客戶端也成功的接受到了伺服器傳送的字元陣列。