Ⅰ 怎樣學習Windows 網路編程
新手必學:windows網路編程經典入門
作者:huyoo
對於一個windows網路編程初學者,下面方法是經典入門。
初學者建議不要用MFC提供的類,而用windows API做一個簡單伺服器和客戶端,這樣有助於對socket編程機制的理解。
為了簡單起見,應用程序是基於MFC的標准對話框。
Winsock用WINDOWS API實現:
(1)伺服器端有兩個線程:
主線程 — 你需要編寫以下函數來實現
#define NETWORK_EVENT USER_MESSAGE+100 file://定義網路事件
sockaddr_in clientaddr; file://暫時存放客戶端IP地址
file://自己定義消息映射函數,將上面定義的網路事件映射到處理函數
file://OnNetEvent為網路事件處理函數,它在下面定義
ON_MESSAGE(NETWORK_EVENT, OnNetEvent);
在你對話框中的初始化函數中調用下面的初始化網路的子函數
BOOL InitNetwork() file://初始化網路
{
file://初始化TCP協議
BOOL ret = WSAStartup(MAKEWORD(2,2), &wsaData);
if(ret != 0)
{
MessageBox("初始化套接字失敗!");
return FALSE;
}
file://創建伺服器端套接字
SOCKET serverSocket
= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(serverSocket == INVALID_SOCKET)
{
MessageBox("創建套接字失敗!");
closesocket(m_Socket);
WSACleanup();
return FALSE;
}
file://綁定到本地一個埠上
sockaddr_in localaddr;
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(1688);
localaddr.sin_addr.s_addr = 0;
if(bind(serverSocket ,(const struct sockaddr*)&localaddr,
sizeof(sockaddr)) == SOCKET_ERROR)
{
MessageBox("綁定地址失敗!");
closesocket(m_Socket);
WSACleanup();
return FALSE;
}
file://注冊網路非同步事件,m_hWnd為應用程序的主對話框或主窗口的句柄
WSAAsyncSelect(serverSocket, m_hWnd, NETWORK_EVENT,
FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE);
listen(serverSocket, 5); file://設置偵聽模式
return TRUE;
}
file://定義網路事件的響應函數
void OnNetEvent(WPARAM wParam, LPARAM lParam)
{
file://調用API函數,得到網路事件類型
int iEvent = WSAGETSELECTEVENT(lParam);
file://得到發出此事件的客戶端套接字
SOCKET pSock = (SOCKET)wParam;
switch(iEvent)
{
case FD_ACCEPT: file://客戶端連接請求
{
OnAccept();
break;
}
case FD_CLOSE: file://客戶端斷開事件:
{
OnClose(pSock);
break;
}
case FD_READ: file://網路數據包到達事件
{
OnReceive(pSock);
break;
}
case FD_WRITE: file://發送網路數據事件
{
OnSend(pSock);
break;
}
default: break;
}
}
void OnAccept(SOCET pSock) file://響應客戶端連接請求函數
{
int len = sizeof(sockaddr);
file://調用API函數,接受連接,並返回一個新套接字
file://還可以獲得客戶端的IP地址
SOCKET clientSocket = accept(serverSocket,
(struct sockaddr*)&clientaddr, &len);
file://為新的socket注冊非同步事件,注意沒有Accept事件
if(WSAAsyncSelect(clientSocket ,m_hWnd, IP_EVENT,
FD_CLOSE | FD_READ | FD_WRITE) == SOCKET_ERROR)
{
MessageBox("注冊非同步事件失敗!");
return;
}
file://自編函數,將此客戶端的相關信息保存下來:套接字、
// IP地址、登陸時間
saveClientSocket(clientSocket,clientAddr,currentTimer);
}
void OnClose(SOCET pSock)
{
file://自編函數,結束與相應的客戶端的通信,釋放相應資源並做相應處理
endClientSocket(pSock);
}
void OnSend(SOCET pSock)
{
file://自編函數,在給客戶端發數據時做一些預處理
handleOnSend(pSock);
}
void OnReceive(SOCET pSock)
{
recv(...); file://調用API函數,讀出網路緩沖區中的數據包
file://自編函數,將此數據包和發出此數據的客戶端
file://clientSocket封裝成一條網路消息
buildNetMsg(...);
file://自編函數,將此網路消息放入一個消息隊列中,由工作線程去處理
saveNetMsg(...);
SetEvent(...); file://用事件對象觸發工作線程
}
客戶端登陸後,隨即把自己的計算機名發給伺服器,伺服器接到後,把它保存下來。這樣伺服器就可以顯示所有在線客戶端的信息了,包括:客戶端計算機名、IP地址、登陸時間等。
注意: 客戶端沒有OnAccept()函數,但有OnConnect()函數。
工作線程 —
在你的應用程序初始化時,創建並啟動一個工作線程
AfxBeginThread(WorkThread,this,THREAD_PRIORITY_NORMAL);
file://this可能為應用程序的主對話框或主窗口的句柄
UINT WorkThread(LPVOID pParam)
{
while(1)
{
file://等待多重事件到來
int ret = WaitForMultipleObject(...);
switch(ret)
{
case OBJECT_0:
{
if(bNewNetMsg) file://查看網路消息隊列是否有新的網路消息
{
readNetMsg(...); file://如有新的網路消息,則讀出
handleNetMsg(...); file://處理此網路消息
}
break;
}
case OBJECT_0 + 1:
{
file://做退出處理
break;
}
default: break;
}
return 0;
}
客戶端為單線程,登陸伺服器時,用connect()函數給伺服器發連接請求;
客戶端沒有OnAccept()函數,但有OnConnect()函數。
在OnConnect()函數里做發連接請求時的預處理;
在OnReceive()函數里響應並處理網路數據;
在OnClose()函數里響應伺服器的關閉事件;
在OnSend()函數里做發數據時的預處理;
如果你還想實現各客戶端之間的在線交流(即所謂的聊天室),你在客戶端還可以基於UDP協議
再做一套多點對多點的區域網組播模型模型,以後在和你聊,你先把上面的程序實現。
以上的I/O非同步模型基於Windows的消息機制,另外還可以用事件模型、重疊模型或完成埠模型,
建議你參考Windows網路編程指南之類的書。
如果你能對上面的機制很熟練,你肯定已經對Winsock編網路程序的機制有一定理解,接下來你可以進行更精彩的編程, 不僅可以在網上傳輸普通數據,而且還
以傳輸語音、視頻數據,你還可以自己做一個聊天室,和你的同學在實驗室的區域網里可以共同分享你的成果。
Ⅱ UDP和Socket通信步驟
這是在網上找到的,希望對你有所幫助。
sockets(套接字)編程有三種,流式套接字(SOCK_STREAM),數據報套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);
WINDOWS環境下TCP/UDP編程步驟:
1. 基於TCP的socket編程是採用的流式套接字。
在這個程序中,將兩個工程添加到一個工作區。要鏈接一個ws2_32.lib的庫文件。
伺服器端編程的步驟:
1:載入套接字型檔,創建套接字(WSAStartup()/socket());
2:綁定套接字到一個IP地址和一個埠上(bind());
3:將套接字設置為監聽模式等待連接請求(listen());
4:請求到來後,接受連接請求,返回一個新的對應於此次連接的套接字(accept());
5:用返回的套接字和客戶端進行通信(send()/recv());
6:返回,等待另一連接請求;
7:關閉套接字,關閉載入的套接字型檔(closesocket()/WSACleanup())。
伺服器端代碼如下:
#include <stdio.h>
#include <Winsock2.h>
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );
return;
}
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;
int len=sizeof(SOCKADDR);
while(1)
{
SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
char sendBuf[50];
sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(addrClient.sin_addr));
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
char recvBuf[50];
recv(sockConn,recvBuf,50,0);
printf("%s\n",recvBuf);
closesocket(sockConn);
}
}
客戶端編程的步驟:
1:載入套接字型檔,創建套接字(WSAStartup()/socket());
2:向伺服器發出連接請求(connect());
3:和伺服器端進行通信(send()/recv());
4:關閉套接字,關閉載入的套接字型檔(closesocket()/WSACleanup())。
客戶端的代碼如下:
#include <stdio.h>
#include <Winsock2.h>
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );
return;
}
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
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();
}
2.基於UDP的socket編程是採用的數據報套接字。
在這個程序中,將兩個工程添加到一個工作區。同時還要鏈接一個ws2_32.lib的庫文件。
伺服器端編程的步驟:
1:載入套接字型檔,創建套接字(WSAStartup()/socket());
2:綁定套接字到一個IP地址和一個埠上(bind());
3:等待和接收數據(sendto()/recvfrom());
4:關閉套接字,關閉載入的套接字型檔(closesocket()/WSACleanup())。
伺服器端代碼如下:
#include <winsock2.h>
#include <stdio.h>
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup( );
return;
}
SOCKET sockSrv=socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(7003);
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
char recvBuf[50];
SOCKADDR addrClient;
int len=sizeof(SOCKADDR);
recvfrom(sockSrv,recvBuf,50,0,(SOCKADDR*)&addrClient,&len);
printf("%s\n",recvBuf);
closesocket(sockSrv);
WSACleanup();
}
對於基於UDP的socket客戶端來說,要進行如下步驟:
1:創建一個套接字(socket);
2:向伺服器發送數據(sendto);
3:關閉套接字;
代碼如下:
#include <winsock2.h>
#include <stdio.h>
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
WSACleanup( );
return;
}
SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN addrClient;
addrClient.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrClient.sin_family=AF_INET;
addrClient.sin_port=htons(8889);
SOCKADDR_IN addrSrv;
sendto(sockClient,"hi",3,0,(SOCKADDR*)&addrClient,sizeof(SOCKADDR));
}
LINUX環境下TCP/UDP編程步驟:
TCP編程步驟:
一. 服務端:
1.socket(int domain,int type,int protocol):建立套接字;
2 .bind(int sockid,struct sockaddr *addrp,socklen_t addrlen):把本機地址和埠跟上一步建立的socket綁定在一起;
3.listen(int sockid,int qsize):監聽某套接字;
4.fd=accept(int sockid,struct sockaddr *callerid,socklen_t *addrlenp):等待某套接字接收信息;
5.recv(int fd,void *buf,size_t nbytes,int flags):從套接字接收數據;
6.close(fd) 和close(sockid)
二.客戶端:
1. socket():建立套接字;
2.connect(int sockid,struct sockaddr *serv_addrp,socklen_t addrlen):連接到伺服器;
3. send(int sockfd,const void *buf,size_t nbytes,int flags):發送數據到伺服器.
4. close(sockid);
UDP編程步驟:
一,服務端:
1. socket():同上;
2. bind():同上;
3. recvfrom(int sockfd,void*buff,size_t nbytes,int flags,struct sockaddr*from,socklen_t*addrlen):在套接字口接收數據,並且記錄下接收到的數據來源;一定要注意這里的參數addrlen,它不僅是函數的輸出,也是函數的輸入!所以要在調用該函數之前對addrlen賦值sizeof(struct sockaddr)。否則返回的地址from將會出錯!
4. close(sockfd);
二. 客戶端:
1. socket();同上;
2. sendto(int sockfd,const void*buff,size_t nbytes,int flags,const struct sockaddr*to,socklen_t addrlen):往指定的地址發送數據;
3. close(sockfd);
Ⅲ 什麼是 網路編程
通過使用套接字來達到進程間通信目的編程就是網路編程。windows提供的基於網路編程的就是套接字也就是winsock,但是現在Winpcap也是一個比較方便的工具。
開發語言不限啊。C、java、vb都可以。
網路編程介紹
Internet網路模型
網路模型:描述網路的結構原理和工作原理
OSI參考模型:七層
Internet網路模型:四層
網路協議:指定層上進行數據交換的規則。
Internet的網路層協議:IP協議;DNS協議(輔助協議)
Internet的傳輸層協議:TCP協議;UDP協議。
套接字基礎
套接字(Sockets):應用程序和網路協議的介面。
Java Sockets:Java應用程序和網路協議的介面,提供若干個類的定義。
Java應用程序利用這些類繼承網路協議的行為,實現網路通信。
TCP Sockets:使用TCP協議實現可靠的網路通信。
UDP Sockets:使用UDP協議實現效率較高的網路通信。
Ⅳ 在windows下用C語言如何實現socket網路編程,需要用到哪些頭文件或者庫
需要用到的頭文件包含:
#include <winsock2.h>
#include <windows.h>
與Linux環境下socket編程相比,windows環境多了一個步驟:啟動或者初始化winsock庫
Winsock,一種標准API,一種網路編程介面,用於兩個或多個應用程序(或進程)之間通過網路進行數據通信。具有兩個版本:
Winsock 1:
Windows CE平台支持。
頭文件:WinSock.h
庫:wsock32.lib
Winsock 2:
部分平台如Windows CE貌似不支持。通過前綴WSA可以區別於Winsock 1版本。個別函數如WSAStartup、WSACleanup、WSARecvEx、WSAGetLastError都屬於Winsock 1.1規范的函數;
頭文件:WinSock2.h
庫:ws2_32.lib
mswsock.h用於編程擴展,使用時必須鏈接mswsock.dll
(4)windowsudp編程擴展閱讀
winsock庫的載入與卸載:
載入:int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
載入成功,返回值為0。
WORD wVersionRequested:載入的winsock版本,使用宏MAKEWORD(x, y),x表示高位元組,y表示低位元組。然而使用時MAKEWORD(2, 2)。高位元組與低位元組相同~~
LPWSADATA lpWSAData:WSADATA結構的指針,傳入參數後,系統幫助我們填充版本信息。有興趣的可以看看結構體內容,不過基本用不著。
卸載:int WSACleanup(void);比起載入,卸載的函數真是輕松愉快。