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