d) 服務(wù)器端發(fā)送消息輸入消息并回車即可發(fā)送。
注意:由于程序順序/循環(huán)執(zhí)行,非事件驅(qū)動(dòng)結(jié)構(gòu),因此必須在接收到對(duì)方發(fā)送的數(shù)據(jù)后,己方方可發(fā)送。
3、 UDP通信1. UDP簡(jiǎn)介UDP是無連接的不可靠的傳輸協(xié)議。采用UDP進(jìn)行通信時(shí),不需要建立連接,可以直接向一個(gè)IP地址發(fā)送數(shù)據(jù),但是不能保證對(duì)方能收到。
對(duì)于基于UDP面向無連接的套接字編程來說,服務(wù)器端和客戶端這種概念不是特別的嚴(yán)格。可以把服務(wù)器端稱為接收端,客戶端就是發(fā)送數(shù)據(jù)的發(fā)送端。
2. UDP通信過程圖 20
服務(wù)器端先初始化Socket,然后與端口綁定(bind),在這時(shí)如果有個(gè)客戶端初始化一個(gè)Socket,客戶端發(fā)送數(shù)據(jù)請(qǐng)求,服務(wù)器端接收請(qǐng)求并處理請(qǐng)求,然后把回應(yīng)數(shù)據(jù)發(fā)送給客戶端,客戶端讀取數(shù)據(jù),一次交互結(jié)束。
注意到,在進(jìn)行端口綁定(bind)之后,服務(wù)器端不需要對(duì)端口進(jìn)行監(jiān)聽(listen),也不需要調(diào)用等待連接(accept)阻塞,等待客戶端連接。而客戶端無需使用連接(connect)事先與服務(wù)器建立連接。
3. UDP服務(wù)器程序流程- 建立套接字文件描述符,使用函數(shù)socket(),生成套接字文件描述符。
- 設(shè)置服務(wù)器地址和偵聽端口,初始化要綁定的網(wǎng)絡(luò)地址結(jié)構(gòu)。
- 綁定偵聽端口,使用bind()函數(shù),將套接字文件描述符和一個(gè)地址類型變量進(jìn)行綁定。
- 接收客戶端的數(shù)據(jù),使用recvfrom()函數(shù)接收客戶端的網(wǎng)絡(luò)數(shù)據(jù)。
- 向客戶端發(fā)送數(shù)據(jù),使用sendto()函數(shù)向服務(wù)器主機(jī)發(fā)送數(shù)據(jù)。
- 關(guān)閉套接字,使用close()函數(shù)釋放資源。UDP協(xié)議的客戶端流程.
4. UDP客戶端程序流程- 建立套接字文件描述符,socket()。
- 設(shè)置服務(wù)器地址和端口,struct sockaddr。
- 向服務(wù)器發(fā)送數(shù)據(jù),sendto()。
- 接收服務(wù)器的數(shù)據(jù),recvfrom()。
- 關(guān)閉套接字,close()。
5. 通信實(shí)驗(yàn)1) 實(shí)驗(yàn)內(nèi)容說明本次實(shí)驗(yàn)進(jìn)行了更為簡(jiǎn)單的驗(yàn)證次實(shí)驗(yàn)啟動(dòng)服務(wù)器后監(jiān)聽某端口后,由客戶端發(fā)送一固定數(shù)據(jù)給服務(wù)器,服務(wù)器接收并顯示后。雙方釋放套接字并結(jié)束程序。
2) 服務(wù)器端程序的編制a) 程序變量定義及函數(shù)聲明b) 程序主函數(shù)c) 其他子函數(shù)其他子函數(shù)包括用于初始化套接字,綁定IP和端口的函數(shù),其中分別調(diào)用了Socket中提供的功能函數(shù)。其具體實(shí)現(xiàn)由附件5給出。
3) 客戶端程序的編制a) 程序變量定義及函數(shù)聲明b) 程序主函數(shù)c) 其他子函數(shù)其他子函數(shù)包括用于初始化套接字,設(shè)置服務(wù)器IP和端口的函數(shù),其中分別調(diào)用了Socket中提供的功能函數(shù)。其具體實(shí)現(xiàn)由附件6給出。
4) 實(shí)驗(yàn)過程a) 啟動(dòng)服務(wù)器并監(jiān)聽端口b) 啟動(dòng)客戶端向服務(wù)器發(fā)送c) 服務(wù)器接收并顯示
圖 21
圖 22
5. 附件五(UDP Server程序)
#include<stdio.h>
#include<winsock.h> /*引入winsock頭文件*/
#pragma comment(lib,"ws2_32.lib")
char Receivebuf[100]; /*接受數(shù)據(jù)的緩沖區(qū)*/
int length;
SOCKET socket_send; /*定義套接字*/
SOCKADDR_IN Server_add; /*服務(wù)器地址信息結(jié)構(gòu)*/
SOCKADDR_IN Client_add; /*客戶端地址信息結(jié)構(gòu)*/
WORD wVersionRequested; /*字(word):unsigned short*/
WSADATA wsaData; /*庫版本信息結(jié)構(gòu)*/
int error; /*表示錯(cuò)誤*/
void Init_Socket(); /*初始化套接字*/
void Bind_Socket(); /*綁定套接字*/
int main()
{
memset(Receivebuf,0,100); /*清空接收緩沖*/
Init_Socket(); /*初始化套接字*/
socket_send=socket(AF_INET,SOCK_DGRAM,0); /*創(chuàng)建套接字*/
Bind_Socket(); /*綁定套接字*/
recvfrom(socket_send,Receivebuf,100,0,(SOCKADDR*)&Client_add,&length);
printf("客戶端:%s\n",Receivebuf); /*接收并顯示數(shù)據(jù)*/
closesocket(socket_send); /*釋放套接字資源*/
WSACleanup(); /*關(guān)閉動(dòng)態(tài)鏈接庫*/
system("pause");
return 0;
}
void Init_Socket()
{
/*-------------------------初始化套接字庫---------------------------*/
/*定義版本類型。將兩個(gè)字節(jié)組合成一個(gè)字,前面是第字節(jié),后面是高字節(jié)*/
wVersionRequested = MAKEWORD( 2, 2 );
/*加載套接字庫,初始化Ws2_32.dll動(dòng)態(tài)鏈接庫*/
error = WSAStartup( wVersionRequested, &wsaData);
if(error!=0)
{
printf("加載套接字失敗!\n");
return 0; /*程序結(jié)束*/
}
/*判斷請(qǐng)求加載的版本號(hào)是否符合要求*/
if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)
{
WSACleanup( ); /*不符合,關(guān)閉套接字庫*/
return 0; /*程序結(jié)束*/
}
printf("加載套接字成功。\n");
}
void Bind_Socket()
{
/*----------------------設(shè)置服務(wù)器地址-----------------------*/
Server_add.sin_family=AF_INET;/*地址家族,對(duì)于必須是AF_INET,注意只有它不是網(wǎng)絡(luò)網(wǎng)絡(luò)字節(jié)順序*/
Server_add.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
Server_add.sin_port=htons(5000);/*端口號(hào)*/
/*綁定套接字*/
bind(socket_send,(SOCKADDR*)&Server_add,sizeof(SOCKADDR));
length=sizeof(SOCKADDR);
printf("綁定成功。\n正在監(jiān)聽\n");
}
6. 附件六(UDP Client程序)
#include<stdio.h>
#include<winsock.h> /*引入winsock頭文件*/
#pragma comment(lib,"ws2_32.lib")
#define Msg "This is a test!" /*待發(fā)送數(shù)據(jù)*/
SOCKET socket_client; /*定義套接字*/
SOCKADDR_IN Server_add; /*服務(wù)器地址信息結(jié)構(gòu)*/
WORD wVersionRequested; /*字(word):unsigned short*/
WSADATA wsaData; /*庫版本信息結(jié)構(gòu)*/
int error; /*表示錯(cuò)誤*/
void Init_Socket(); /*初始化套接字*/
void Set_Server(); /*設(shè)置服務(wù)器地址和端口*/
int main()
{
Init_Socket(); /*初始化套接字*/
socket_client=socket(AF_INET,SOCK_DGRAM,0); /*創(chuàng)建套接字*/
Set_Server(); /*設(shè)置服務(wù)器地址和端口*/
/*發(fā)送數(shù)據(jù)*/
sendto(socket_client,Msg,strlen(Msg)+1,0,(SOCKADDR*)&Server_add,sizeof(SOCKADDR));
printf("已發(fā)送數(shù)據(jù)至服務(wù)器\n");
closesocket(socket_client); /*釋放套接字資源*/
WSACleanup(); /*關(guān)閉動(dòng)態(tài)鏈接庫*/
system("pause");
return 0;
}
void Init_Socket()
{
/*-------------------------初始化套接字庫---------------------------*/
/*定義版本類型。將兩個(gè)字節(jié)組合成一個(gè)字,前面是第字節(jié),后面是高字節(jié)*/
wVersionRequested = MAKEWORD( 2, 2 );
/*加載套接字庫,初始化Ws2_32.dll動(dòng)態(tài)鏈接庫*/
error = WSAStartup( wVersionRequested, &wsaData);
if(error!=0)
{
printf("加載套接字失敗!\n");
return 0; /*程序結(jié)束*/
}
/*判斷請(qǐng)求加載的版本號(hào)是否符合要求*/
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )
{
WSACleanup( ); /*不符合,關(guān)閉套接字庫*/
return 0; /*程序結(jié)束*/
}
printf("加載套接字成功。\n");
}
void Set_Server()
{
/*----------------------設(shè)置服務(wù)器地址-----------------------*/
Server_add.sin_family=AF_INET;/*地址家族,對(duì)于必須是AF_INET,注意只有它不是網(wǎng)絡(luò)網(wǎng)絡(luò)字節(jié)順序*/
Server_add.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
Server_add.sin_port=htons(5000); /*端口號(hào)*/
printf("服務(wù)器設(shè)置成功。\n");
}
4. 附件四(TCP Client程序)
#include<stdio.h>
#include<winsock.h> /*引入winsock頭文件*/
#pragma comment(lib,"ws2_32.lib")
char Sendbuf[100]; /*發(fā)送數(shù)據(jù)的緩沖區(qū)*/
char Receivebuf[100]; /*接受數(shù)據(jù)的緩沖區(qū)*/
int SendLen; /*發(fā)送數(shù)據(jù)的長(zhǎng)度*/
int ReceiveLen; /*接收數(shù)據(jù)的長(zhǎng)度*/
char IPaddress[16]; /*IP地址數(shù)組*/
char Port[6]; /*端口數(shù)組*/
SOCKET socket_send; /*定義套接字*/
SOCKADDR_IN Server_add; /*服務(wù)器地址信息結(jié)構(gòu)*/
WORD wVersionRequested; /*字(word):unsigned short*/
WSADATA wsaData; /*庫版本信息結(jié)構(gòu)*/
int error; /*表示錯(cuò)誤*/
int Init_Socket(); /*初始化套接字*/
void Create_Socket(); /*創(chuàng)建套接字*/
void Connect_Socket(); /*連接服務(wù)器*/
void Close_Socket(); /*釋放套接字*/
int main()
{
Init_Socket(); /*初始化套接字*/
Create_Socket(); /*創(chuàng)建套接字*/
Connect_Socket(); /*連接服務(wù)器*/
while(1) /*具體通信過程*/
{
/*---------------發(fā)送數(shù)據(jù)過程----------*/
printf("請(qǐng)輸入消息:");
gets(Sendbuf); //獲取輸入的數(shù)據(jù)
SendLen = send(socket_send,Sendbuf,100,0); //啟動(dòng)發(fā)送
if(SendLen < 0)
{
printf("發(fā)送失敗!\n"); //發(fā)送失敗
break;
}
/*--------------接收數(shù)據(jù)過程---------------*/
ReceiveLen =recv(socket_send,Receivebuf,100,0); //結(jié)束數(shù)據(jù)存緩沖區(qū)
if(ReceiveLen<0)
{
printf("連接關(guān)閉或接收失敗\n程序退出\n"); //接收或連接失敗
break;
}
else
{
printf("來自服務(wù)器:%s\n",Receivebuf); //顯示收到的數(shù)據(jù)
}
}
Close_Socket(); /*釋放套接字*/
return 0;
}
int Init_Socket()
{
/*------------初始化套接字庫---------------*/
/*定義版本類型。將兩個(gè)字節(jié)組合成一個(gè)字,前面是第字節(jié),后面是高字節(jié)*/
wVersionRequested = MAKEWORD( 2, 2 );
/*加載套接字庫,初始化Ws2_32.dll動(dòng)態(tài)鏈接庫*/
error = WSAStartup( wVersionRequested, &wsaData);
if(error!=0)
{
printf("加載套接字失敗。\n");
return 0; /*程序結(jié)束*/
}
else
{
printf("加載套接字成功。\n");
}
/*判斷請(qǐng)求加載的版本號(hào)是否符合要求*/
if(LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)
{
WSACleanup( ); /*不符合,關(guān)閉套接字庫*/
return 0; /*程序結(jié)束*/
}
else
{
printf("加載版本號(hào)符合。\n");
}
}
void Create_Socket()
{
/*-------------進(jìn)行連接服務(wù)器--------------*/
/*客戶端創(chuàng)建套接字,但是不需要綁定的,只需要和服務(wù)器建立起連接就可以了。*/
/*socket_sendr表示的是套接字,Server_add服務(wù)器的地址結(jié)構(gòu)*/
socket_send=socket(AF_INET,SOCK_STREAM,0);
}
void Connect_Socket()
{
/*------------設(shè)置服務(wù)器地址---------------*/
Server_add.sin_family=AF_INET;/*地址家族,對(duì)于必須是AF_INET,注意只有它不是網(wǎng)絡(luò)網(wǎng)絡(luò)字節(jié)順序*/
/*服務(wù)器的地址,將一個(gè)點(diǎn)分十進(jìn)制表示為IP地址,inet_ntoa是將地址轉(zhuǎn)成字符串*/
puts("輸入IP地址:");
gets(IPaddress);
puts("輸入端口:");
gets(Port);
Server_add.sin_addr.S_un.S_addr = inet_addr(IPaddress);
Server_add.sin_port=htons(atoi(Port)); /*端口號(hào)*/
/*-------------創(chuàng)建用于連接的套接字--------*/
/*AF_INET表示指定地址族,SOCK_STREAM表示流式套接字TCP,特定的地址家族相關(guān)的協(xié)議。*/
if(connect(socket_send,(SOCKADDR*)&Server_add,sizeof(SOCKADDR)) == SOCKET_ERROR)
{
printf("服務(wù)器連接失敗。\n");
}
else
{
printf("服務(wù)器連接成功。\n");
}
}
void Close_Socket()
{
/*---------釋放套接字,關(guān)閉動(dòng)態(tài)庫----------*/
closesocket(socket_send); /*釋放套接字資源*/
WSACleanup(); /*關(guān)閉動(dòng)態(tài)鏈接庫*/
}
3. 附件三(TCP Server程序)
#include<stdio.h>
#include<winsock.h> /*引入winsock頭文件*/
#pragma comment(lib,"ws2_32.lib")
#define IPaddress "127.0.0.1" /*IP地址*/
#define Port "5000" /*端口*/
char Sendbuf[100]; /*發(fā)送數(shù)據(jù)的緩沖區(qū)*/
char Receivebuf[100]; /*接受數(shù)據(jù)的緩沖區(qū)*/
int SendLen; /*發(fā)送數(shù)據(jù)的長(zhǎng)度*/
int ReceiveLen; /*接收數(shù)據(jù)的長(zhǎng)度*/
int Length; /*表示SOCKADDR的大小*/
SOCKET socket_server; /*定義服務(wù)器套接字*/
SOCKET socket_receive; /*定義用于連接套接字*/
SOCKADDR_IN Server_add; /*服務(wù)器地址信息結(jié)構(gòu)*/
SOCKADDR_IN Client_add; /*客戶端地址信息結(jié)構(gòu)*/
WORD wVersionRequested; /*字(word):unsigned short*/
WSADATA wsaData; /*庫版本信息結(jié)構(gòu)*/
int error; /*表示錯(cuò)誤*/
int Init_Socket(); /*初始化套接字*/
void Create_Socket(); /*創(chuàng)建套接字*/
int Bind_Socket(); /*綁定IP和端口*/
int Listen_Socket(); /*設(shè)置監(jiān)聽狀態(tài)*/
int Wait_Socket(); /*等待客戶端連接*/
void Close_Socket(); /*釋放套接字*/
int main()
{
Init_Socket(); /*初始化套接字*/
Create_Socket(); /*創(chuàng)建套接字*/
Bind_Socket(); /*綁定IP和端口*/
Listen_Socket(); /*設(shè)置監(jiān)聽狀態(tài)*/
Wait_Socket(); /*等待客戶端連接*/
while(1) /*具體通信過程*/
{
/*--------接收數(shù)據(jù)---------*/
ReceiveLen =recv(socket_receive,Receivebuf,100,0); //接收數(shù)據(jù)存緩沖區(qū)
if(ReceiveLen<0) //連接或接收失敗
{
printf("客戶端中斷連接或接收失敗\n程序退出\n");
break;
}
else
{
printf("來自客戶端:%s\n",Receivebuf); //顯示接收到的數(shù)據(jù)
}
/*--------發(fā)送數(shù)據(jù)---------*/
printf("請(qǐng)輸入消息:");
gets(Sendbuf); //獲取輸入的數(shù)據(jù)
SendLen=send(socket_receive,Sendbuf,100,0); //啟動(dòng)發(fā)送
if(SendLen<0)
{
printf("發(fā)送失敗。\n"); //本次發(fā)送失敗
break;
}
}
Close_Socket(); /*釋放連接*/
return 0;
}
int Init_Socket()
{
/*------------初始化套接字庫---------------*/
/*定義版本類型。將兩個(gè)字節(jié)組合成一個(gè)字,前面是第字節(jié),后面是高字節(jié)*/
wVersionRequested = MAKEWORD( 2, 2 );
/*加載套接字庫,初始化Ws2_32.dll動(dòng)態(tài)鏈接庫*/
error = WSAStartup( wVersionRequested, &wsaData);
if(error!=0)
{
printf("加載套接字失敗。\n");
return 0; /*程序結(jié)束*/
}
else
{
printf("加載套接字成功。\n");
}
/*判斷請(qǐng)求加載的版本號(hào)是否符合要求*/
if(LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)
{
WSACleanup( ); /*不符合,關(guān)閉套接字庫*/
return 0; /*程序結(jié)束*/
}
else
{
printf("加載版本號(hào)符合。\n");
}
return 1;
}
void Create_Socket()
{
/*------------設(shè)置連接地址-----------------*/
Server_add.sin_family=AF_INET;/*地址家族,對(duì)于必須是AF_INET,注意只有它不是網(wǎng)絡(luò)網(wǎng)絡(luò)字節(jié)順序*/
Server_add.sin_addr.S_un.S_addr=inet_addr(IPaddress); /*主機(jī)地址*/
Server_add.sin_port=htons(atoi(Port));/*端口號(hào)*/
/*------------創(chuàng)建套接字-------------------*/
/*AF_INET表示指定地址族,SOCK_STREAM表示流式套接字TCP,特定的地址家族相關(guān)的協(xié)議。*/
socket_server=socket(AF_INET,SOCK_STREAM,0);
}
int Bind_Socket()
{
/*---綁定套接字到本地的某個(gè)地址和端口上----*/
/*socket_server為套接字,(SOCKADDR*)&Server_add為服務(wù)器地址*/
if(bind(socket_server,(SOCKADDR*)&Server_add,sizeof(SOCKADDR) )==SOCKET_ERROR)
{
printf("綁定失敗。\n");
return 0;
}
else
{
printf("套接字綁定成功。\n");
printf("當(dāng)前主機(jī)地址:");
printf(IPaddress);
printf("\n當(dāng)前主機(jī)端口:");
printf(Port);
printf("\n");
}
return 1;
}
int Listen_Socket()
{
/*------------設(shè)置套接字為監(jiān)聽狀態(tài)---------*/
/*監(jiān)聽狀態(tài),為連接做準(zhǔn)備,最大等待的數(shù)目為5*/
if(listen(socket_server,5)<0)
{
printf("監(jiān)聽失敗\n");
return 0;
}
else
{
printf("監(jiān)聽成功\n");
return 1;
}
}
int Wait_Socket()
{
/*------------接受連接---------------------*/
Length=sizeof(SOCKADDR);
/*接受客戶端的發(fā)送請(qǐng)求,等待客戶端發(fā)送connect請(qǐng)求*/
socket_receive=accept(socket_server,(SOCKADDR*)&Client_add,&Length);
if(socket_receive==SOCKET_ERROR)
{
printf("客戶端連接失敗。");
return 0;
}
else
{
printf("客戶端連接成功。\n");
return 1;
}
}
void Close_Socket()
{
/*---------釋放套接字,關(guān)閉動(dòng)態(tài)庫----------*/
closesocket(socket_receive); /*釋放客戶端的套接字資源*/
closesocket(socket_server); /*釋放套接字資源*/
WSACleanup(); /*關(guān)閉動(dòng)態(tài)鏈接庫*/
}
7. 附件七(單片機(jī)原理圖)