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