網路程式設計之入門篇(一)

2021-05-28 17:51:31 字數 4571 閱讀 9940

伺服器端操作 socket(套接字)

1.在初始化階段呼叫wsastartup()

此函式在應用程式中初始化windows sockets dll ,只有此函式呼叫成功後,應用程式才可以再呼叫其他windows sockets dll中的api函式。在程式中呼叫該函式的形式如下:wsastartup((word)((1<<8|1),(lpwsadata)&wsadata),其中(1<<8|1)表示我們用的是winsocket1.1版本,wsaata用來儲存系統傳回的關於winsocket的資料。

#include //包含windows

#pragma comment(lib, "ws2_32.lib")//動態鏈結windows sockets dll

2、建立socket

初始化winsock的動態連線庫後,需要在伺服器端建立乙個監聽的socket,為此可以呼叫socket()函式用來建立這個監聽的socket,並定義此socket所使用的通訊協議。此函式呼叫成功返回socket物件,失敗則返回invalid_socket(呼叫wsagetlasterror()可得知原因,所有winsocket 的api函式都可以使用這個函式來獲取失敗的原因)。

socket pascal far socket( int af, int type, int protocol )

引數: af:目前只提供 pf_inet(af_inet);

type:socket 的型別 (sock_stream、sock_dgram);

protocol:通訊協定(如果使用者不指定則設為0);

如果要建立的是遵從tcp/ip協議的socket,第二個引數type應為sock_stream,如為udp(資料報)的socket,應為sock_dgram。

3、繫結埠

接下來要為伺服器端定義的這個監聽的socket指定乙個位址及埠(port),這樣客戶端才知道待會要連線哪乙個位址的哪個埠,為此我們要呼叫bind()函式,該函式呼叫成功返回0,否則返回socket_error。

int pascal far bind( socket s, const struct sockaddr far *name,int namelen );

參 數: s:socket物件名;

name:socket的位址值,這個位址必須是執行這個程式所在機器的ip位址;

namelen:name的長度;

如果使用者不在意位址或埠的值,那麼可以設定位址為inaddr_any,及port為0,windows sockets 會自動將其設定適當之位址及port (1024 到 5000之間的值)。此後可以呼叫getsockname()函式來獲知其被設定的值。

4、監聽

當伺服器端的socket物件繫結完成之後,伺服器端必須建立乙個監聽的佇列來接收客戶端的連線請求。listen()函式使伺服器端的socket 進入監聽狀態,並設定可以建立的最大連線數(目前最大值限制為 5, 最小值為1)。該函式呼叫成功返回0,否則返回socket_error。

int pascal far listen( socket s, int backlog );

參 數: s:需要建立監聽的socket;

backlog:最大連線個數;

伺服器端的socket呼叫完listen()後,如果此時客戶端呼叫connect()函式提出連線申請的話,server 端必須再呼叫accept() 函式,這樣伺服器端和客戶端才算正式完成通訊程式的連線動作。為了知道什麼時候客戶端提出連線要求,從而伺服器端的socket在恰當的時候呼叫 accept()函式完成連線的建立,我們就要使用wsaasyncselect()函式,讓系統主動來通知我們有客戶端提出連線請求了。該函式呼叫成功返回0,否則返回socket_error。

int pascal far wsaasyncselect( socket s, hwnd hwnd,unsigned int wmsg, long levent );

引數: s:socket 物件;

hwnd :接收訊息的視窗控制代碼;

wmsg:傳給視窗的訊息;

levent:被註冊的網路事件,也即是應用程式向視窗傳送訊息的網路事件,該值為下列值fd_read、fd_write、fd_oob、 fd_accept、fd_connect、fd_close的組合,各個值的具體含意為fd_read:希望在套接字s收到資料時收到訊息;fd_write:希望在套接字s上可以傳送資料時收到訊息;fd_accept:希望在套接字s上收到連線請求時收到訊息;fd_connect:希望在套接字s上連線成功時收到訊息;fd_close:希望在套接字s上連線關閉時收到訊息;fd_oob:希望在套接字s上收到帶外資料時收到訊息。具體應用時,wmsg應是在應用程式中定義的訊息名稱,而訊息結構中的lparam則為以上各種網路事件名稱。所以,可以在視窗處理自定義訊息函式中使用以下結構來響應socket的不同事件:  

switch(lparam) 

5、伺服器端接受客戶端的連線請求

當client提出連線請求時,server 端hwnd視窗會收到winsock stack送來我們自定義的乙個訊息,這時,我們可以分析lparam,然後呼叫相關的函式來處理此事件。為了使伺服器端接受客戶端的連線請求,就要使用 accept() 函式,該函式新建一socket與客戶端的socket相通,原先監聽之socket繼續進入監聽狀態,等待他人的連線要求。該函式呼叫成功返回乙個新產生的socket物件,否則返回invalid_socket。

socket pascal far accept( scoket s, struct sockaddr far *addr,int far *addrlen );

引數:s:socket的識別碼;

addr:存放來連線的客戶端的位址;

addrlen:addr的長度

6、結束 socket 連線

結束伺服器和客戶端的通訊連線是很簡單的,這一過程可以由伺服器或客戶機的任一端啟動,只要呼叫closesocket()就可以了,而要關閉 server端監聽狀態的socket,同樣也是利用此函式。另外,與程式啟動時呼叫wsastartup()憨數相對應,程式結束前,需要呼叫 wsacleanup() 來通知winsock dll釋放socket所占用的資源。這兩個函式都是呼叫成功返回0,否則返回socket_error。

int pascal far closesocket( socket s );

引數:s:socket 的識別碼;

int pascal far wsacleanup( void );

引數: 無

(二)實現例子

伺服器端:  

#include

#include

#pragma comment(lib, "ws2_32.lib")

void main()

if ( lobyte( wsadata.wversion ) != 1 ||

hibyte( wsadata.wversion ) != 1 )

socket socksrv=socket(af_inet,sock_stream,0);

sockaddr_in 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));// 繫結埠

listen(socksrv,5);

sockaddr_in addrclient;// 連線上的客戶端ip位址

int len=sizeof(sockaddr);

while(1)

客戶端**:

#include

#include

#pragma comment(lib, "ws2_32.lib")

void main()

if ( lobyte( wsadata.wversion ) != 1 ||hibyte( wsadata.wversion ) != 1 )

socket sockclient=socket(af_inet,sock_stream,0);// af_inet ..tcp連線

//初始化連線與埠號

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));//連線伺服器

char recvbuf[50];

recv(sockclient,recvbuf,50,0);//接受資料

printf("%s\n",recvbuf);

send(sockclient,"hello",strlen("hello")+1,0);//傳送資料

closesocket(sockclient);//關閉連線

wsacleanup();

}

多執行緒程式設計 之 入門篇

自己第一次涉及c語言的多執行緒程式設計,實屬入門了解級別的 之前只做過j a的runnable的多執行緒程式設計。本次我們可以把螢幕看成是乙個資源,這個資源被兩個執行緒所共用,include include using namespace std dword winapi fun lpvoid lp...

socket程式設計入門篇(三)

這篇部落格介紹多執行緒併發伺服器的實現。下面貼 服務端 include include include include include include include include include includeusing namespace std define serverip 127.0.0...

HOOK API入門篇 一

windows系統是建立在事件驅動的機制上的,說穿了就是整個系統都是通過訊息的傳遞來實現的。而鉤子是windows系統中非常重要的系統介面,用它可以截獲並處理送給其他應用程式的訊息,來完成普通應用程式難以實現的功能。鉤子可以監視系統或程序中的各種事件訊息,截獲發往目標視窗的訊息並進行處理。這樣,我們...