網路程式設計之基於TCP 的Sockets程式設計
流套接字(SOCK_STREAM): 流套接字用於提供面向連線、可靠的資料傳輸服務。該服務將保證資料能夠實現無差錯、無重複傳送,並按順序接收。流套接字之所以能夠實現可靠的資料服務,原因在於其使用了傳輸控制協議,即
資料報套接字(SOCK_DGRAM):資料報套接字提供了一種無連線的服務。該服務並不能保證資料傳輸的可靠性,資料有可能在傳輸過程中丟失或出現數據重複,且無法保證順序地接收到資料。資料報套接字使用UDP(User Datagram Protocol)協議進行資料的傳輸。由於資料包套接字不能保證資料傳輸的可靠性,對於有可能出現的資料丟失情況,需要在程式中做相應的處理。
原始套接字(SOCK_RAW):原始套接字與標準套接字(標準套接字指的是前面介紹的流套接字和資料報套接字)的區別在於:原始套接字可以讀寫核心沒有處理的
我們如果想要用套接字實現網路通訊,那就應該至少需要一對,一個在伺服器端(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);
}
}
執行伺服器端和客戶端程式,可以知道伺服器和客戶端已經啟動,客戶端也成功的接受到了伺服器傳送的字元陣列。