1. 程式人生 > >套接字(二):Socket 套接字程式設計(附例項)

套接字(二):Socket 套接字程式設計(附例項)

TCP/IP地址家族統一的套接字地址結構定義如下:
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);
	}
}