網絡編程可分為基於TCP的網絡程序設計和基於UDP的網絡程序設計。TCP是基於字節流的面向連接的,常用於可靠的網絡傳輸,而UDP是基於數據報的無連接的網絡傳輸,常用語即時通信。
無論是基於TCP或者是基於UDP的程序設計,它都是有固定的步驟可循的。只要理解這些步驟,實現起來也是比較簡單的。下面將介紹基於TCP和UDP的網絡編程的詳細步驟以及實現實例。
在介紹網絡編程之前,首先要說明一點:Winsock函數是Windows提供的網絡編程的借口,無論是基於TCP的還是UDP的網絡編程,在程序設計之前,都要首先加載Winsock庫。
一、基於TCP的網絡應用程序
網絡應用程序都是基於C/S(客戶端/服務器)模式的,因此在進行網絡應用程序開發時,不僅要開發服務器應用程序也要開發客戶端應用程序。開發服務器應用程序和客戶端應用程序在步驟上略有不同。下面介紹一下基於TCP的網絡應用程序開發的詳細步驟:
服務器端應用程序: 客戶端應用程序:
1、創建socket套接字 1、創建socket套接字
2、將套接字綁定(bind)到指定的本機IP地址和端口上
3、將套接字設為監聽模式(listen),准備接受客戶端的請求 2、向服務器發送連接請求(connect)
4、等待客戶端請求的到來(accept),並返回新的套接字進行通信
5、服務器和客戶端相互通信(send/recv) 3、服務器和客戶端相互通信(send/recv)
6、返回繼續等待新的客戶端請求到來
7、關閉socket套接字 4、關閉socket套接字
注釋:服務器要綁定端口,監聽客戶端請求,當接受到請求後才開始通信。而客戶端只需要先發送請求,只要請求被接收後就可以通信了。
在理解示例代碼之前,先介紹一些知識點和函數:
第一點:在網絡編程中,要用到IP地址和端口號,比如在bind()和accept()函數中都需要有到IP地址和端口號,在Windows API中有一個SOCKADDR_IN結構體中可以保存IP地址和端口號的信息。
第二點:服務器要綁定的IP地址應該用(INADDR_ANY)屬性,表示服務器可以接受任何端口發送來的連接請求,這是因為有的機器可能有多個網卡,因此可能有多個IP地址,這樣設定可以方便後面的程序開發。
第三點:網絡通信中用到的是網絡字節序,intel的機器本機字節序和網絡字節序的存放格式是不一樣的,所以要用想用的函數進行轉化。
inet_addr()將點分十進制的IP地址轉化為u_long型
inet_ntoa()將in_addr結構類型的參數轉化為點分十進制的IP地址
htonl()將u_long型的IP地址從主機字節序轉換為網絡字節序
htons()將u_short型的IP地址從主機字節序轉換為網絡字節序
第四點:網絡編程要用到Winsock庫,,所以不僅要加載winsock的頭文件,並且要綁定ws2_32.lib動態鏈接庫。綁定動態鏈接庫有兩種方法。第一種就是在工程的“屬性”裡設置“Link”的鏈接庫加上ws2_32.lib就可以了。第二種方法就是在工程的源文件中加上代碼:#pragma comment(lib,"ws2_32.lib")就可以了。
/**************************************************************
基於TCP的服務器應用程序示例代碼
****************************************************************/
#include "stdafx.h"
#include <stdlib.h>
#include <Winsock2.h>
#include <stdio.h>
void main()
{
/**************************************************************
加載Winsock庫
****************************************************************/
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;
}
/**************************************************************
第一步:創建Winsock套接字
****************************************************************/
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,(const sockaddr*)&addrSrv,sizeof(SOCKADDR));
/**************************************************************
第三步:將套接字設置為監聽模式,准備接受客戶端的請求
****************************************************************/
listen(sockSrv,5);
/**************************************************************
第四步:接受客戶端的請求
第五步:接收客戶端的消息和向客戶端發送消息
第六步:返回等待
第七步:關閉套接字
****************************************************************/
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR);
while(1)
{
SOCKET sockCon=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
char sendBuf[100];
sprintf(sendBuf,"This is server,Welcome%s",inet_ntoa(addrClient.sin_addr));
send(sockCon,sendBuf,strlen(sendBuf)+1,0);
char recvbuf[100];
recv(sockCon,recvbuf,strlen(recvbuf)+1,0);
printf("%s\n",recvbuf);
closesocket(sockCon);
}
system("PAUSE");
}
/**************************************************************
基於TCP的客戶端應用程序示例代碼
****************************************************************/
#include "stdafx.h"
#include <stdlib.h>
#include <Winsock2.h>
#include <stdio.h>
void main()
{
/**************************************************************
加載Winsock庫
****************************************************************/
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;
}
/**************************************************************
第一步:創建Winsock套接字
****************************************************************/
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,(const sockaddr*)&addrSrv,sizeof(SOCKADDR));
/**************************************************************
第三步:客戶端和服務器的相互通信
****************************************************************/
char recvbuf[100];
recv(sockClient,recvbuf,strlen(recvbuf)+1,0);
printf("%s",recvbuf);
send(sockClient,"My name is zhangsan Client",strlen("My name is zhangsan Client")+1,0);
closesocket(sockClient);
WSACleanup();
system("PAUSE");
}
先運行服務器程序再運行客戶端程序,運行結果如下:
二、基於UDP的網絡應用程序
上面介紹了基於TCP的網絡應用程序,為了便於比較,下面介紹基於UDP的網絡應用程序的設計方法。
和上面一樣,先接受基於UDP的網絡應用程序的開發步驟:
服務器端應用程序: 客戶端應用程序:
1、創建socket套接字 1、創建socket套接字
2、將套接字綁定(bind)到指定的本機IP地址和端口上 2、向服務器發送消息(sendto)
3、如果檢測到有消息到來就接收消息(recvfrom)
4、關閉socket套接字 3、關閉socket套接字
注釋:由於基於UDP的網絡應用程序是面向無連接的,所以不需要服務器的監聽,也不需要客戶端的連接請求。實現起來比TCP的面向連接的簡單,適用於即時通信。主要用到的函數和方法和TCP的設計方法大致一樣。示例代碼如下:
/**************************************************************
基於UDP的服務器應用程序示例代碼
****************************************************************/
#include "stdafx.h"
#include <stdlib.h>
#include <Winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
void main()
{
/**************************************************************
加載Winsock庫
****************************************************************/
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;
}
/**************************************************************
第一步:創建Winsock套接字
****************************************************************/
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(6000);
bind(sockSrv,(const sockaddr*)&addrSrv,sizeof(SOCKADDR));
/**************************************************************
第三步:等待並接受客戶端發送的消息
****************************************************************/
SOCKADDR_IN addrClient;
char recvBuf[100];
int len=sizeof(SOCKADDR);
recvfrom(sockSrv,recvBuf,100,0,(sockaddr*)&addrClient,&len);
printf("%s",recvBuf);
char sendBuf[100];
sprintf(sendBuf,"This is UDP Serve! Welcome %s",inet_ntoa(addrClient.sin_addr));
sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,
(const sockaddr*)&addrClient,sizeof(SOCKADDR));
closesocket(sockSrv);
WSACleanup();
system("pause");
}
/**************************************************************
基於UDP的客戶端應用程序示例代碼
****************************************************************/
#include "stdafx.h"
#include <stdlib.h>
#include <Winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
void main()
{
/**************************************************************
加載Winsock庫
****************************************************************/
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;
}
/**************************************************************
第一步:創建Winsock套接字
****************************************************************/
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(6000);
sendto(sockClient,"My name is UDP Client!",strlen("My name is UDP Client!")+1,0,
(const sockaddr*)&addrClient,sizeof(SOCKADDR));
char recvBuf[100];
int len=sizeof(SOCKADDR);
recvfrom(sockClient,recvBuf,100,0,(sockaddr*)&addrClient,&len);
printf("%s",recvBuf);
closesocket(sockClient);
WSACleanup();
system("pause");
}
運行結果如下:
<script type=text/javascript> if ($ != jQuery) { $ = jQuery.noConflict(); } var isLogined = false; var cb_blogId = 96439; var cb_entryId = 2208677; var cb_blogApp = "chengfeng736"; var cb_blogUserGuid = "1dbb9853-fbd5-e011-8ee0-842b2b196315"; var cb_entryCreatedDate = '2011/10/12 15:13:00'; </script> 摘自:乘風736