【windows socket+UDP伺服器客戶端】

Love_Hulidear發表於2014-05-09

Windows Socket+UDP伺服器客戶端


     Winsock是 Windows下套接字標準
         
         1.UDP socket程式設計

         UDP(使用者資料包協議)是一個無連線,不可靠的資料傳輸,其特點是簡單,快捷。相比與TCP,UDP不需要建立連線(不需connect、accept函式),資料傳送接收之後,不需要終止連線。基於UDP的程式,避免了TCP執行的開銷,在效率與速度上具有更好的表現。
         UDP是無連線的,可能會有資料的丟失,延遲,這些需要應用程式自己處理。
         
         2.UDP基本函式
          
建立socket
         SOCKET  socket (int af, int type, int protocol);
         第一個引數af:  表示族地址,網路程式設計一般使用AF_INET巨集。
         第二個引數type:  表示連線型別,TCP可選面向連線SOCK_STREAM,UDP資料包SOCK_DGRAM。
         第三個引數protocol:  表示協議,在使用AF_INET族地址UDP連線,設為IPPROTO_UDP。
繫結socket:
         int  bind(SOCKET s, const struct sockaddr *saddr,int namelen);
         第一個引數:  需要繫結的socket。
         第二個引數:  對應AF_INET,使用struct sockaddr_in包含協議,IP,埠等資訊。
         第三個引數:  對應AF_INET,使用struct sockaddr_in結構大小。
         該函式將socket與協議,IP地址,Port埠號繫結起來,相對於給socket“命名”唯一的標識,這樣其他的程式就可以通過這個標識找到這個socket。
傳送資料
         int  sendto(SOCKET s, const char  *buf,  int len,
                              int flags, const struct sockaddr  *to, int tolen);
         第一個引數:  socket為對方的socket。
         第二個引數:  傳送資料的緩衝區。
         第三個引數:  資料緩衝區大小。
         第四個引數:  緊急狀態,一般這為0。
         第五個引數:  可選,對應AF_INET,對方IP,埠等socket地址標識sockaddr_in。
         第六個引數:  可選,對應AF_INET,使用sockaddr_in結構大小。
         該函式用於UDP傳送資料。
接收資料
         int  recvfrom(SOCKET s, char *buf, int len, 
                                  int flags, struct sockaddr *from, int *fromlen );         
         第一個引數:  socket為對方的socket。
         第二個引數:  接收資料的緩衝區。
         第三個引數:  資料緩衝區大小。
         第四個引數:  緊急狀態,一般這為0。
         第五個引數:  可選,對應AF_INET,返回對方IP,埠等socket地址標識sockaddr_in。
         第六個引數:  可選,對應AF_INET,使用sockaddr_in結構大小。
         該函式用於UDP接收資料。
繫結socket
         int  bind(SOCKET s, const struct sockaddr *saddr,int namelen);
         第一個引數:  需要繫結的socket。
         第二個引數:  對應AF_INET,使用struct sockaddr_in包含協議,IP,埠等資訊。
         第三個引數:  對應AF_INET,使用struct sockaddr_in結構大小。
         該函式將socket與協議,IP,埠號繫結起來,相對於給socket“命名”唯一的標識,這樣其他的程式就可以通過這個標識找到這個socket。
關閉套接字
          int  closesocket(SOCKET s);
          引數為socket。
          該函式用於關閉套接字。
          
          3.牛刀小試
          先在VC6.0執行伺服器程式,再開啟一個VC6.0執行客戶端程式:
          UDPsever伺服器等待來自客戶端的資訊,收到資訊後列印出來,然後向客戶端傳送現在的時間。
          UDPclient客戶端向伺服器傳送一個“Hello,server!”資訊,然後接收來自伺服器的時間資訊並列印,重複三次。

執行效果:

UDP客戶端程式:
#include
#include
#pragma comment(lib,"ws2_32.lib")
int main()
{
	WSADATA wsa;
	SOCKET serversoc;
	SOCKADDR_IN serveraddr;
	SOCKADDR_IN peeraddr;
	int peer_len=sizeof(peeraddr);
	char Recv_buf[64];
	//char *Server_IP="127.0.0.1";
	char *Send_data="Hello,server!";
	int Send_len=strlen(Send_data);
	int time_out=2000;    //接收超時
	int result;
    
	WSAStartup(WINSOCK_VERSION,&wsa);	//初始化WS2_32.DLL
    
	//命名協議,IP,埠
    serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(13);
	serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	if(serveraddr.sin_addr.s_addr==INADDR_NONE)
	{
			printf("不可用地址!\n");
			return -1;
	}
    
	//建立套接字
	serversoc = socket(AF_INET,SOCK_DGRAM,0);
	
    result = setsockopt(serversoc,SOL_SOCKET,SO_RCVTIMEO,(char*)&time_out,sizeof(time_out));
    for(int i=0;i<3;i++)
	{
	    //傳送資料
		result = sendto(serversoc,Send_data,Send_len,0,(SOCKADDR *)&serveraddr,sizeof(serveraddr));

		//接收資料
		result = recvfrom(serversoc,Recv_buf,64,0,(SOCKADDR *)&peeraddr,&peer_len);
		if(result >= 0)
		{
			Recv_buf[result]= 0;
			printf("接收資料為:  %s \n",Recv_buf);
		}
	}
    closesocket(serversoc);
	WSACleanup();
    return 0;
}
UDP伺服器程式:
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
int main()
{
	WSADATA wsa;
	WSAStartup(WINSOCK_VERSION,&wsa);	//初始化WS2_32.DLL

	SOCKET serversoc;
	SOCKET clientsoc;
	SOCKADDR_IN serveraddr;
	SOCKADDR_IN clientaddr;
	int client_len = sizeof(clientaddr);
	int server_len = sizeof(serveraddr);
	char *Send_data;
	int Send_len;
	char Recv_buf[64];
	int result;
	time_t nowtime;

	//命名協議,IP,埠
    serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(13);
	serveraddr.sin_addr.s_addr = INADDR_ANY;

	//建立socket
	serversoc = socket(AF_INET,SOCK_DGRAM,0);
	

	//繫結socket
	result=bind(serversoc, (SOCKADDR *)&serveraddr, server_len);
	if(result==SOCKET_ERROR)
	{
		printf("套接字繫結失敗!\n");
		closesocket(serversoc);
		return -1;
	}

	printf("Server is running.....\n");

	clientsoc = socket(AF_INET,SOCK_DGRAM,0);
	while(1)
	{   
		//接收資料
		result = recvfrom(serversoc,Recv_buf,64,0,(SOCKADDR *)&clientaddr,&client_len);
		if(result >= 0)
		{
			Recv_buf[result]= 0;
			printf("接收資料為:  %s \n",Recv_buf);
		
		    //傳送資料
			nowtime=time(0);
			Send_data=ctime(&nowtime);
			Send_len=strlen(Send_data);
	     	result = sendto(clientsoc,Send_data,Send_len,0,(SOCKADDR *)&clientaddr,sizeof(clientaddr));
			printf("Server is running.....\n");
		}
	}

	closesocket(serversoc);
	WSACleanup();
	return 0;
}


相關文章