套接字(二):Socket 套接字程式設計(附例項)
阿新 • • 發佈:2019-02-13
TCP/IP地址家族統一的套接字地址結構定義如下:
sin_family 指定使用該套接字地址的地址家族。 這裡必須設定為AF_INET,表示程式所使用的地址家族是TCP/IP; sin_zero[8] 主要是為了與第一個版本的套接字地址結構大小相同而設定,實際使用時,將這8個位元組設定為0即可。 sin_addr 表示32為的IP地址結構 結構定義如下:
通常,使用一個u_long型別的字元進行描述IP地址即可。
Socket 套接字程式設計中,傳輸資料的排列順序以網路位元組順序和主機位元組順序為主。 資料在主機儲存時,是以主機位元組順序儲存的。 資料要通過網路傳送,需要轉換為網路位元組順序。否則會造成損壞。 網路位元組是將重要的位元組優先儲存,而主機位元組順序則相反。 Winsock 中的網路位元組和主機位元組的轉換函式 主機位元組->網路位元組 u_short htons(u_short hostshort); //u_short 型別的IP地址 u_long htonl(u_long hostlong); //u_long unsigned long inet_addr(const char FAR* cp);//字串IP 網路位元組->主機位元組 u_long ntohl(u_long hostlong);//u_long u_short ntols(u_short hostshort);//u_short char FAR* inet_ntoa(struct in_addr in);//字串IP 具體使用:
Socket 相關函式 1.建立套接字 CSocket 類建立套接字是通過其建構函式建立的 CSocket :: CSocket(); 建立CSocket物件 CSocket sock; 或 CSocket *sock; sock = new CSocket; 2.繫結地址資訊 如果套接字物件是伺服器套接字,那麼該套接字應該呼叫該類的函式Bind()將套接字物件與伺服器地址資訊繫結在一起。 BOOL Bind(const SOCKADDR* lpSockAddr,int nSockAddrLen); lpSockAddr 地址結構 nSockAddrLen 地址結構長度 地址繫結成功後,還要呼叫函式Listen()在指定埠監聽客戶端的連線請求。 函式Listen()的原型如下: BOOL Listen(int nConnectionBackLog = 5); nContectionBackLog 表示套接字監聽客戶請求的最大數目。有效範圍1~5。 具體呼叫
3.連線伺服器 客戶端建立套接字成功後,呼叫函式Connect()向伺服器傳送連線請求。 BOOL Connect(const SOCKADDR* lpSockAddr,int nSockAddrLen); lpSockAddr 連線的伺服器地址結構 nSockAddrLen 伺服器地址結構長度 具體呼叫:
4.資料交換 通過Send()和Receive()進行資料交換 函式原型 virtual int Send(const void lpBuf,int nBuflen,int nFlags = 0); virtual int Receive(void* lpBuf,int nBuflen,int nFlags = 0); lpBuf: 資料緩衝區地址 nBuflen:資料緩衝區的大小 nFlags : 資料傳送或接收標誌,一般情況都設定為0 ...
5.關閉套接字物件 服務端和客戶端的通訊完成後,呼叫函式Close()將套接字物件關閉 sock.Close(); 注意:CSocket類的標頭檔案 afxsock.h 使用時,必須引入此檔案 #include<afxsock.h> 伺服器端程式碼:
struct sockaddr_in
{
short sin_family; //指定地址家族,即地址格式
unsigned short sin_port; //埠號碼
struct in_addr sin_addr; //IP地址
char sin_zero[8]; //需要指定為0
}
sin_family 指定使用該套接字地址的地址家族。 這裡必須設定為AF_INET,表示程式所使用的地址家族是TCP/IP; sin_zero[8] 主要是為了與第一個版本的套接字地址結構大小相同而設定,實際使用時,將這8個位元組設定為0即可。 sin_addr 表示32為的IP地址結構 結構定義如下:
struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; //用4個u_char字元描述IP地址 struct { u_short s_w1,s_w2; } S_un_w; //用2個u_short型別描述IP地址 u_long S_addr;//用1個u_long型別描述IP地址 } S_un; #define s_addr S_un.S_addr };
通常,使用一個u_long型別的字元進行描述IP地址即可。
sockaddr_in addr;
addr.sin_addr.S_un.S_addr = inet_addr("218.6.132.5");
Socket 套接字程式設計中,傳輸資料的排列順序以網路位元組順序和主機位元組順序為主。 資料在主機儲存時,是以主機位元組順序儲存的。 資料要通過網路傳送,需要轉換為網路位元組順序。否則會造成損壞。 網路位元組是將重要的位元組優先儲存,而主機位元組順序則相反。 Winsock 中的網路位元組和主機位元組的轉換函式 主機位元組->網路位元組 u_short htons(u_short hostshort); //u_short 型別的IP地址 u_long htonl(u_long hostlong); //u_long unsigned long inet_addr(const char FAR* cp);//字串IP 網路位元組->主機位元組 u_long ntohl(u_long hostlong);//u_long u_short ntols(u_short hostshort);//u_short char FAR* inet_ntoa(struct in_addr in);//字串IP 具體使用:
sockaddr_in addrTo; addrTo.sin_family=AF_INET; addrTo.sin_port=htons(8900); addrTo.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); char address[] = inet_ntoa(addrTo.sin_addr.S_un.S_addr);
Socket 相關函式 1.建立套接字 CSocket 類建立套接字是通過其建構函式建立的 CSocket :: CSocket(); 建立CSocket物件 CSocket sock; 或 CSocket *sock; sock = new CSocket; 2.繫結地址資訊 如果套接字物件是伺服器套接字,那麼該套接字應該呼叫該類的函式Bind()將套接字物件與伺服器地址資訊繫結在一起。 BOOL Bind(const SOCKADDR* lpSockAddr,int nSockAddrLen); lpSockAddr 地址結構 nSockAddrLen 地址結構長度 地址繫結成功後,還要呼叫函式Listen()在指定埠監聽客戶端的連線請求。 函式Listen()的原型如下: BOOL Listen(int nConnectionBackLog = 5); nContectionBackLog 表示套接字監聽客戶請求的最大數目。有效範圍1~5。 具體呼叫
CSocket sock; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(80); addr.sin_addr.S_un.s_addr = inet_addr("127.0.0.1"); sock.Bind((SOCKADDR*)addr,sizeof(addr)); //繫結套接字的地址結構 sock.Listen(5);
3.連線伺服器 客戶端建立套接字成功後,呼叫函式Connect()向伺服器傳送連線請求。 BOOL Connect(const SOCKADDR* lpSockAddr,int nSockAddrLen); lpSockAddr 連線的伺服器地址結構 nSockAddrLen 伺服器地址結構長度 具體呼叫:
CSocket sock;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.S_un_S_addr = inet_addr("127.0.0.1");
sock.Connect((SOCKADDR*)addr,sizeof(addr));//連線伺服器
4.資料交換 通過Send()和Receive()進行資料交換 函式原型 virtual int Send(const void lpBuf,int nBuflen,int nFlags = 0); virtual int Receive(void* lpBuf,int nBuflen,int nFlags = 0); lpBuf: 資料緩衝區地址 nBuflen:資料緩衝區的大小 nFlags : 資料傳送或接收標誌,一般情況都設定為0 ...
char buff[] = 'a';
sock.Send(&buff,sizeof(buff),0);
sock.Receive(&buff,sizeof(buff),0);
5.關閉套接字物件 服務端和客戶端的通訊完成後,呼叫函式Close()將套接字物件關閉 sock.Close(); 注意:CSocket類的標頭檔案 afxsock.h 使用時,必須引入此檔案 #include<afxsock.h> 伺服器端程式碼:
// SocketSever.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"WS2_32.lib")
int main(int argc, char* argv[])
{
//1.使用者初始化套接字型檔
WSADATA data; //定義WSADATA結構體物件
WORD w = MAKEWORD(2,0); //定義版本號
char sztext[] = "歡迎你\r\n"; //定義並初始化傳送到客戶端的字元陣列
::WSAStartup(w,&data); //初始化套接字型檔
//2.建立套接字
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;
//3.繫結地址資訊及啟動監聽
::bind(s,(sockaddr*)&addr,sizeof(addr)); //繫結套接字
::listen(s,5);
printf("伺服器已經啟動 \r\n");
//4.監聽及接收請求
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);
}
//5.關閉套接字物件
::closesocket(s);
::closesocket(s1);
//6.釋放套接字型檔
::WSACleanup();
if(getchar())
{
return 0;
}
else
{
::Sleep(100);
}
}
}
客戶端程式碼:
// SocketClient.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"WS2_32.lib")
int main(int argc, char* argv[])
{
//1.使用者初始化套接字型檔
WSADATA data; //定義WSADATA結構體物件
WORD w = MAKEWORD(2,0); //定義版本號
::WSAStartup(w,&data); //初始化套接字型檔
//2.建立套接字
SOCKET s; //定義連線套接字
char sztext[10] = {0};
s = ::socket(AF_INET,SOCK_STREAM,0); //建立TCP套接字
sockaddr_in addr; //定義套接字地址結構
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");
//3.連線伺服器
::connect(s,(sockaddr*)&addr,sizeof(addr));
//4.接收伺服器訊息
::recv(s,sztext,sizeof(sztext),0);
printf("%s \r\n",sztext);
//5.關閉套接字物件
::closesocket(s);
//6.釋放套接字型檔
::WSACleanup();
if(getchar())
{
return 0;
}
else
{
::Sleep(100);
}
}