![]() |
|
教學(xué)公告
一、Client/Server網(wǎng)絡(luò)編程模型:
Client/Server網(wǎng)絡(luò)編程基于socket編程基礎(chǔ),socket(套接字編程)源于Unix,想深入學(xué)習(xí)的同學(xué)可以查找相關(guān)的資料進(jìn)行學(xué)習(xí)。
Windows socket編程思想也是源于Unix socket,相關(guān)的函數(shù)都是直接拿過(guò)來(lái)用,只有部分的變量定義有些區(qū)別。套接字有兩種類(lèi)型:
流式套接字(SOCK_STREAM),基于TCP傳輸協(xié)議,面向連接,可靠的傳輸方式。
數(shù)據(jù)報(bào)式套接字(SOCK_DGRAM),基于UDP,面向無(wú)連接,不可靠。
下面是關(guān)于TCP、UDP socket編程的流程圖:
TCP:
UDP:
在windows上進(jìn)行socket編程,需要引入相關(guān)的庫(kù)文件:
#include
相關(guān)函數(shù)講解:
加載套接字庫(kù)并進(jìn)行版本協(xié)商
Int WSAStartup(WORD wVersionRequested,
//請(qǐng)求的版本號(hào),低字節(jié)代表主版本,高字節(jié)代表副版本,一般我們用MAKEWORD(x,y)//宏來(lái)指定版本號(hào),如:MAKEWORD(2,1)代表2.1的版本
LPWSADATA lpWSAData
//out,一個(gè)WSADATA結(jié)構(gòu)體指針,用于接收實(shí)際加載的套接字 庫(kù)版本號(hào)
)
創(chuàng)建套接字
SOCKET socket(int af, //指定協(xié)議族,也即網(wǎng)際域,對(duì)于windows平臺(tái)總是AF_INET 或 PF_INET
Int type,//指定要?jiǎng)?chuàng)建的套接字類(lèi)型
Int protocol//指定協(xié)議類(lèi)型,我們一般設(shè)為0,讓他根據(jù)我們前兩個(gè)參數(shù)自動(dòng)設(shè)置
)
綁定到本機(jī)地址和端口
int bind(SOCKET s, //已創(chuàng)建的套接字描敘符
const struct sockaddr FAR *name, //要綁定的本機(jī)地址信息
Int namelen //第二個(gè)參數(shù)的長(zhǎng)度
)
其中要注意第二個(gè)參數(shù),由于第二個(gè)參數(shù)適用于所有網(wǎng)絡(luò)協(xié)議,所以我們可以根據(jù)需要進(jìn)行替換,如我們常常這樣定義一個(gè)AF_INET 的地址信息:
SOCKADDR_IN SrvAddr;
SrvAddr.family=AF_INET;
SrvAddr.port=hotns(666); //其中666代表端口號(hào)
SrvAddr.sin_addr.S_un.S_addr=htonl(192.168.1.101);
//或SrvAddr.sin_addr.S_un.S_addr=INADDR_ANY;(指綁定到本機(jī)的任一快網(wǎng)卡上,并且////其本身就是網(wǎng)絡(luò)字節(jié)序,故無(wú)需轉(zhuǎn)換,我推薦這種寫(xiě)法)
Inet_addr和inet_ntoa函數(shù)
Unsigned long Inet_addr(sconst char FAR * cp);
Inet_addr可以把一個(gè)點(diǎn)分十進(jìn)制表示的IP(如:192.168.1.101)轉(zhuǎn)換為unsinged long 類(lèi)型的數(shù)據(jù),且該返回值可以直接賦值給S_addr
Char FAR * inet_ntoa(struct in_addr in);
Inet_ntoa 從他函數(shù)的聲明就知道他完成一個(gè)和inet_addr相反的轉(zhuǎn)換 。
將指定的套接字設(shè)為見(jiàn)聽(tīng)聽(tīng)模式
Int listen(SOCKET s,int backlog);
第一個(gè)參數(shù) s: 已經(jīng)創(chuàng)建的套接字描述符
第二個(gè)參數(shù) backlog 設(shè)置等待連接隊(duì)伍的最大長(zhǎng)度,注意:不是一個(gè)端口上可以同時(shí)連接的數(shù)目。
Accept函數(shù)
就收客服端發(fā)送的連接請(qǐng)求
SOCKET accept(
SOCKET s,
Struct sockaddr FAR * addr,// 返回請(qǐng)求連接方的IP和端口信息
Int FAR * addrlen
);
Send函數(shù)
通過(guò)一個(gè)已經(jīng)建立連接的套接字發(fā)送數(shù)據(jù)
Int send(
SOCKET s,//注意:是以建立連接的套接字
Const char FAR * buf,//目的地IP和端口信息
Int len,
Int falgs//該設(shè)置影響發(fā)送行為,我們一般設(shè)為0
)
Recv 函數(shù)
Int recv(
SOCKET s,
Char FAR *buf,//發(fā)送數(shù)據(jù)的緩存地址
Int len,//發(fā)送數(shù)據(jù)長(zhǎng)度
Int flags//該設(shè)置影響發(fā)送行為,我們一般設(shè)為0
)
Connect 函數(shù)
和一個(gè)特定的套接字建立連接
Int connect(
SOCKET s,
Const struct sockaddr FAR * name,//目的地址信息
Int namelen
)
Recvfrom函數(shù)
接受一次數(shù)據(jù)并保存數(shù)據(jù)源地址信息
Int recvfrom(
SOCKET s,
Char FAR*buf,
Int len,
Int flags,
Struct sockaddr FAR* from//用于保存數(shù)據(jù)源地址信息
Int FAR* fromlen
);
注意:最后一個(gè)參數(shù)是in,out類(lèi)型,我們要在傳參之前賦初始值
如:int len=Sizeof(SOCKADDR);
Sendto函數(shù)
向以一個(gè)特定的目的方發(fā)送數(shù)據(jù)
Int sendto(
SOCKET s,
Const char FAR * buf,//要發(fā)送的數(shù)據(jù)
Int len,//數(shù)據(jù)長(zhǎng)度
Int flags,
Connect struct sockaddr FAR * to,//目的地址信息
Int tolen
)
二、編程要求:
客戶(hù)端ping服務(wù)器端,服務(wù)器端顯示客戶(hù)端發(fā)送數(shù)據(jù)的時(shí)間戳(如19:00:32),然后給客戶(hù)端響應(yīng)消息(pong)(可以隨便是什么消息),客戶(hù)端接收響應(yīng)并輸出,并顯示時(shí)間時(shí)延,比如:延時(shí)5s。
客戶(hù)端:
輸入: ping 127.0.0.1
輸出: ping success or ping failed.
服務(wù)端發(fā)送的消息
延時(shí):xx s
服務(wù)端:
顯示客戶(hù)端發(fā)送的消息(時(shí)間戳):
如:客戶(hù)端發(fā)送數(shù)據(jù)的時(shí)間為19:00:32
PingServer.c
//#include "stdafx.h"
#include
#include
#include
#include
#pragma comment()
//處理客戶(hù)端發(fā)送的數(shù)據(jù)并響應(yīng)
int PingServer()
{
//創(chuàng)建套接字
//綁定IP和端口
//開(kāi)始監(jiān)聽(tīng)
//循環(huán)接收數(shù)據(jù)
//接收數(shù)據(jù)
//打印客戶(hù)端發(fā)送的數(shù)據(jù),顯示時(shí)間戳
//發(fā)送數(shù)據(jù)
}
int main(int argc, char* argv[])
{
PingServer();
return 0;
}
PingClient.c
// PingClient.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//
#include "stdafx.h"
//#include "stdafx.h"
#include
#include
#include
#include
#include
#pragma comment
#define MAXN 1024
//#define IP_Address "1"
//客戶(hù)端ping程序,socket編程流程
int PingClient()
{
//得到服務(wù)器的地址
char *serverIP = GetServerIP(strServerIP);
//連接服務(wù)器的IP地址
//得到發(fā)送的數(shù)據(jù),要求發(fā)送的數(shù)據(jù)為客戶(hù)端的時(shí)間戳
GetSendData(sendData); //process sending data
//cout << sendData;
//發(fā)送
send(sclient, sendData, strlen(sendData), 0);
//接受
int ret = recv(sclient, recData, 255, 0);
//得到接受時(shí)間
t2 = GetCurrentTime();
//得到服務(wù)器端發(fā)送的數(shù)據(jù),打印數(shù)據(jù)接收的時(shí)
int main(int argc, char* argv[])
{
PingClient();
return 0;
}