網絡 基於UDP協議的socket編程

一、UDP協議

       UDP協議的特點:用戶數據包協議

            1、UDP協議是無連接的。也就說在數據發送之前並不需要建立連接(當然,在發送數據結束的時候也就不存在鏈接的釋放),因此減少了開銷和數據發送之前的時延。

            2、UDP使用盡最大努力的交付,但是不保證可靠性的交付,因此主機不需要維持複雜的鏈接狀態表。(網上的的可靠性建立在應答的基礎上,不提供可靠×××付,即不需要應答,因此不需要維護狀態表)

            3、UDP是面向報文發送方的UDP對於應用程序進程交下來的報文,即不合並,也不拆分,而是保留這些報文的邊界。這也就是說,應用層交付給UDP多長的報文,UDP就照樣發送,即一次發送一個報文。同時,在接收方,對於IP層交上來的UDP用戶數據報,在去除首部後就原封不動的交付給應用層的應用進程了。也就說,UDP一次交付一個完整的報文。因此報文的大小必須合適,負責會降低數據的傳輸效率。如果報文太長,在IP層需要對報文分片,就會降低IP層的效率。反之,若報文太短,UDP把它交給IP層後,會使得IP數據報的首部相對過長,同樣會降低IP層的效率。

            4、UDP沒有擁塞控制

二、基於UDP的socket編程的一般流程

        1.server端

            a.獲取有效的IP地址與端口號(port)(服務器端需要約定好的端口號與IP,方便客戶直接與該IP下的該端口建立連接)

            b.將IP與port轉爲網絡通用格式

            c.聲明監聽文件描述符 (int listen_sock),將該文件描述符”註冊“爲

套接字文件(listen_sock=socket(AF_INET,SOCK_DGRAM,0))

           參數:

            AF_INET:IPv4套接字類型(說明地址類型格式)

            SOCK_DGRAM:UDP協議類型(提供無連接的盡力交付)

            0:表示該套接字只支持一種協議

            d.給listen_sock綁定相應的信息( IP,port),因爲socket套接字是由內核接管處理的,因此我們無法直接操作,寫入信息需要以下操作:

            1>聲明struct sockaddr_in 結構體,將對因信息賦值給結構體對應單元

                 local.sin_family=AF_INET;

                local.sin_port=htons(port);

                local.sin_addr.s_addr=ip;

            2>調用bind(int sockfd,struct sockaddr* addr,socklen_t addrlen)函數,將ip,port信息寫入(即綁定)套接字的

            f.使用recvfrom()接收數據。

    wKioL1dD4ZiyAzFTAAAfxUUEj1Q713.png        server端代碼實例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
void usage(char* arg)
{
	printf("Missing Parameters: %s [remote ip :] [remote port :]",arg);
}
int main(int argc,char* argv[])
{
	if(argc!=3){
		usage(argv[0]);
		exit(1);
	}
	in_addr_t _ip=inet_addr(argv[1]);
	int _port=atoi(argv[2]);
	int sock=socket(AF_INET,SOCK_DGRAM,0); 	
	struct sockaddr_in server;
	socklen_t len=sizeof(server);
	server.sin_family=AF_INET;
	server.sin_port=_port;
	server.sin_addr.s_addr=_ip;
	if(bind(sock,(struct sockaddr*)&server,len)<0){
		perror("bind");
		exit(2);
	}
	char buf[1024];
	while(1){
		ssize_t size=recvfrom( sock,buf, 1023,0,\
			(struct sockaddr *)&server, &len);
		
		if(size<0){
			perror("read");
			break;
		}else if(size==0){
			printf("server %d close: ip: %s !\n",sock,inet_ntoa(server.sin_addr));
		}
		else{
			printf("get a connect %d... ip:%s,port:%d\n",sock\
				,inet_ntoa(server.sin_addr),ntohs(server.sin_port));
			buf[size]=0;
			printf("server# %s\n",buf);
		}
	
	}
	return 0;
}

    2.client端

            a.獲取有效的IP地址與端口號(port)(此處爲需要發送的目標服務器的ip,與廣知的port)

            b.將IP與port轉爲網絡通用格式

            c.聲明文件描述符 (int _sock),將該文件描述符”註冊“爲

套接字文件(_sock=socket(AF_INET,SOCK_DGRAM,0))

            d.聲明struct sockaddr_in _server結構體,connect()將目標服務器ip與port寫入使用,並與_sock綁定,同時與目標服務器建立連接。

            wKiom1dD47OQSSFoAAARTQL_c1s664.png

     e.使用sendto()向目標發送UDP報文。

wKiom1dD5DGCriWuAAAgsMZIgmQ584.png

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
void usage(char* arg)
{
	printf("Missing Parameters: %s [remote ip :] [remote port :]",arg);
}
int main(int argc,char* argv[])
{
	if(argc!=3){
		usage(argv[0]);
		exit(1);
	}
	in_addr_t _ip=inet_addr(argv[1]);
	int _port=atoi(argv[2]);
	
	int sock=socket(AF_INET,SOCK_DGRAM,0);
	if(sock<-1){
		perror("socket");
		exit(2);
	}
	struct sockaddr_in server;
	socklen_t len=sizeof(server);
	server.sin_family=AF_INET;
	server.sin_port=_port;
	server.sin_addr.s_addr=_ip;
	if( connect( sock, (struct sockaddr *)&server, len)<0){
		perror("connect");
		exit(3);
	}	
	char buf[1024];

	while(1){
		printf("please Enter:");
		gets(buf);
		if(strcmp(buf,"quit")==0){
			sendto(sock, buf,0,0 ,(struct sockaddr *)&server, len);
			break;
		}
		sendto(sock, buf,strlen(buf),0 ,(struct sockaddr *)&server, len);
	}
	close(sock);
	return 0;
}









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章