使用TCP/IP協議的應用程式通常採用兩種應用編程介面(API):socket和TLI(運輸層接)。前者有時稱作"Berkeley socket",表明它是從伯克利版發展而來的。後者起初是由AT & T開發的,有時稱作XTI(X/Open運輸層介面),以承認X/Open這個自己定義標準的國際電腦生產商所做的工作。XTI實際上是TLI的一個超集。而在windows作業系統中,實現了windows版本的socketAPI,又稱winsock。 大家都知道不管是TCP/IP還是OSI的ISO協議都是分層模式的,用層的概念屏蔽的下層的細節,只要完成自層的功能即可,因而程式員在做網路編程時並不需要去關心網路底層的具體實現,只需要關心軟體的功能即可極大的簡化了程式的編寫。因而我們在學習網路socket編程時並不一定要很多的網路方面的知識,甚至是TCP/IP協議的知識也不需要太多。因而在著我就不介紹那方面的知識了,如果要瞭解網上也四處都有那些被別人應用了N遍的經典的介紹。
在這隻介紹基於TCP和UDP的簡單的編程實現。 現今的網路程式一般都是基於C/S模型,即客戶機-伺服器模型。這種結構將主要運算操作放在中心電腦上。同集中式大型計算系統比較,"客戶-伺服器"結構的主要優點
是提供了良好的實用性、靈活性、互動性和可擴充性。"客戶-伺服器"以資料庫伺服器取代集中式檔案分享權限設定進而實現了電腦系統之間的松耦合。
"客戶-伺服器"(Client/Server)是典型的Web資訊系統模式。"客戶-伺服器"一詞在20世紀80年代首先被提出,起初,主要指個人電腦和Web的串連,在互連網中,主要指電腦系統之間通過Web的資訊互動傳遞模式;"客戶"是指資訊服務的索取方,"伺服器"指服務的提供方,
根據軟體的不同設定,一台電腦可以是客戶也可以是伺服器。隨著Web科技的發展,"客戶-伺服器"軟體架構成為一種靈活、分布式和模組化的資訊系統結構。 Windows Sockets是Microsoft
Windows的網路程式設計介面,它是從Berkeley Sockets擴充而來的,以動態連結程式庫的形式提供給我們使用。Windows
Sockets在繼承了Berkeley Sockets主要特徵的基礎上,又對它進行了重要擴充。這些擴充主要是提供了一些非同步函數,並增加了符合Windows訊息驅動特性的網路事件非同步選擇機制。Windows Sockets
1.1和Berkeley Sockets都是基於TCP/IP協議的;Windows Sockets 2從Windows
Sockets 1.1發展而來,與協議無關並向下相容,可以使用任何底
層傳輸協議提供的通訊能力,來為上層應用程式完成網路資料通訊,而不關心底層網路鏈路的通訊情況,真正實現了底層網路通訊對應用程式的透明。 通訊端的類型總共有三類:1)
流式通訊端(SOCK_STREAM) 提供連線導向、可靠的Data Transmission Service,資料無差錯、無重複的發送,且按發送順序接收。這種類型是基於TCP協議的。2)
資料報式通訊端(SOCK_DGRAM) 提供無串連服務。資料包以獨立包形式發送,不提供無錯保證,資料可能丟失或重複,並且接收順序混亂。
這種類型是基於UDP協議的3)
原始通訊端(SOCK_RAW)。用於編寫基於IP協議的程式。
它可以訪問ICMP和ICMP等協議包,可以編寫核心不處理的IP資料包,還可以建立自訂的IP資料包首部。
基於
TCP(
連線導向
)
的
socket
編程的流程:
伺服器端程式:1、建立通訊端(socket)。 2、將通訊端綁定到一個本地地址和連接埠上(bind)。3、將通訊端設為監聽模式,準備接收客戶請求(listen)。4、等待客戶請求到來;當請求到來後,接受串連請求,返回一個新的對應於此次串連的通訊端(accept)。5、用返回的通訊端和用戶端進行通訊(send/recv)。6、返回,等待另一客戶請求。7、關閉通訊端。程式碼: //1.建立通訊端 SOCKET sockSrv =
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(INVALID_SOCKET ==
WSAGetLastError()) MessageBox(NULL,
"Create Socket failed!", "Error", MB_OK); //2.綁定通訊端到一個連接埠號碼 SOCKADDR_IN addrSrv; memset(&addrSrv, 0,
sizeof(addrSrv)); addrSrv.sin_addr.S_un.S_addr =
htonl(INADDR_ANY); addrSrv.sin_family = AF_INET; addrSrv.sin_port =
htons(6000); bind(sockSrv,
(SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); //3.設定通訊端為監聽模式 listen(sockSrv, /*SOMAXCONN*/
5); //4.等待使用者的串連到來 SOCKADDR_IN addrClient; int sockLen =
sizeof(SOCKADDR); while(1) { SOCKET sockConn =
accept(sockSrv, (SOCKADDR*)&addrClient, &sockLen); if(INVALID_SOCKET ==
WSAGetLastError())
MessageBox(NULL, "Connect client failed!", "Error", MB_OK); //5.用返回的通訊端和使用者通訊,發送資料或是接受資料 char sendBuf[100]; wsprintf(sendBuf,
"welcome %s to my computer",
inet_ntoa(addrClient.sin_addr)); send(sockConn,
sendBuf, sizeof(sendBuf) + 1, 0); if(SOCKET_ERROR ==
WSAGetLastError())
MessageBox(NULL, "Server send data failed!", "Error", MB_OK); char recvBuf[100]; recv(sockConn,
recvBuf, 100, 0); if(SOCKET_ERROR ==
WSAGetLastError())
MessageBox(NULL, "Server recieve data failed!", "Error", MB_OK); printf("%s/n",
recvBuf); //6.關閉申請的通訊端資源 closesocket(sockConn); } 用戶端程式:1、建立通訊端(socket)。 2、向伺服器發出串連請求(connect)。3、和伺服器端進行通訊(send/recv)。4、關閉通訊端。程式碼://1.建立通訊端 SOCKET sockClient =
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(INVALID_SOCKET ==
WSAGetLastError()) MessageBox(NULL,
"Create Socket failed!", "Error", MB_OK); //2.向伺服器發送串連請求 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr =
inet_addr("127.0.0.1"); addrSrv.sin_family = AF_INET; addrSrv.sin_port =
htons(6000); connect(sockClient,
(SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); //3.和伺服器進行通訊,接收或是發送資料 char recvBuf[100]; recv(sockClient, recvBuf,
100, 0); if(SOCKET_ERROR ==
WSAGetLastError())
MessageBox(NULL, "Server recieve data failed!", "Error", MB_OK); printf("%s/n", recvBuf); char sendBuf[] = "Hello
Server"; send(sockClient, sendBuf,
sizeof(sendBuf) + 1, 0); if(SOCKET_ERROR ==
WSAGetLastError())
MessageBox(NULL, "Server send data failed!", "Error", MB_OK); //4.關閉通訊端的資源,以及卸載通訊端動態連結程式庫 closesocket(sockClient); WSACleanup();
基於
UDP(
面向無串連
)
的
socket
編程
伺服器端(接收端)程式:1、建立通訊端(socket)。 2、將通訊端綁定到一個本地地址和連接埠上(bind)。3、等待接收資料(recvfrom)。4、關閉通訊端。程式碼://1.建立通訊端 SOCKET sockSrv =
socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(INVALID_SOCKET ==
WSAGetLastError()) MessageBox(NULL,
"Create Socket failed!", "Error", MB_OK); //2.綁定通訊端到指定的連接埠 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr =
htonl(INADDR_ANY); addrSrv.sin_family = AF_INET; addrSrv.sin_port =
htons(5000); bind(sockSrv,
(SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); if(SOCKET_ERROR ==
WSAGetLastError()) MessageBox(NULL, "bind
fuction failed!", "Error", MB_OK); //3.等待接收資料 char recvBuf[100]; SOCKADDR_IN addrClient; int fromLen = 100; recvfrom(sockSrv, recvBuf,
100, 0, (SOCKADDR*)&addrClient, &fromLen); if(SOCKET_ERROR ==
WSAGetLastError()) MessageBox(NULL,
"recvfrom fuction failed!", "Error", MB_OK); printf("%s/n", recvBuf); //4.關閉通訊端 closesocket(sockSrv); WSACleanup(); 用戶端(發送端)程式:1、建立通訊端(socket)。 2、向伺服器發送資料(sendto)。3、關閉通訊端。程式碼://1.建立通訊端 SOCKET sockClient =
socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(INVALID_SOCKET ==
WSAGetLastError()) MessageBox(NULL,
"Create Socket failed!", "Error", MB_OK); //2.向伺服器發送資料 char sendBuf[100] = "UDP
Server, Good evening!"; SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr =
inet_addr("127.0.0.1"); addrSrv.sin_family = AF_INET; addrSrv.sin_port =
htons(5000); int toLen = 100; sendto(sockClient, sendBuf,
sizeof(sendBuf) + 1, 0, (SOCKADDR*)&addrSrv, toLen); //3.關閉通訊端 closesocket(sockClient); WSACleanup();