使用 acl 編寫 UDP 網絡程序

      在當今網絡世界,雖然大部分網絡應用都是基於 TCP 的,但有時 UDP 的網絡通信也有用武之處。acl 的網絡庫中不僅提供了基於 TCP 的網絡套接字流,同時也提供了 UDP 的網絡庫(目前 acl 庫的網絡部分僅提供了基本的 UDP 功能,如果想實現 UDP 重傳及可靠性機制,大家可以參考 udt --https://sourceforge.net/projects/udt/ 庫)。

      使用 acl 網絡庫無論編寫客戶端還是服務器程序,都需要首先調用 acl_vstream_bind 接口綁定本機地址,該函數的定義如下:

/**
 * 針對 UDP 通信,該函數用來綁定本地 UDP 地址,如果綁定成功,則創建
 * ACL_VSTREAM 對象, 用戶可以象調用 ACL_VSTREAM 對象的讀寫接口
 * @param addr {const char*} 本地 UDP 地址,格式:ip:port
 * @param rw_timeout {int} 讀寫超時時間(秒)
 * @return {ACL_VSTREAM*} 返回 NULL 表示綁定失敗
 */
ACL_API ACL_VSTREAM *acl_vstream_bind(const char *addr, int rw_timeout);

       然後就可以調用 acl_vstream_read/acl_vstream_write 兩個函數以 UDP 方式進行網絡數據的讀寫了,因爲 UDP 傳輸是不保證順序及可靠性的,所以 acl 網絡庫中的其它讀寫函數就不被用在 UDP 讀寫操作中。

 

      下面一個簡單的 UDP 服務端程序:

static void udp_server(void)
{
	const char *addr = "127.0.0.1:1088";
	char  buf[4096];
	int   ret;
	ACL_VSTREAM *stream = acl_vstream_bind(addr, 0);  /* 綁定 UDP 套接口 */

	if (stream == NULL) {
		printf("acl_vstream_bind %s error %s\r\n", addr, acl_last_serror());
		return;
	}

	printf("bind udp addr %s ok\r\n", addr);

	while (1) {
		/* 等待客戶端數據 */
		ret = acl_vstream_read(stream, buf, sizeof(buf) - 1);
		if (ret == ACL_VSTREAM_EOF) {
			printf("acl_vstream_read error %s\r\n", acl_last_serror());
			break;
		}

		/* 輸出服務器綁定地址及遠程客戶端地址 */
		printf("local addr: %s, peer addr: %s, total: %d\r\n",
			ACL_VSTREAM_LOCAL(stream), ACL_VSTREAM_PEER(stream), i);

		/* 回寫數據至客戶端 */
		ret = acl_vstream_write(stream, buf, ret);
		if (ret == ACL_VSTREAM_EOF) {
			printf("acl_vtream_writen error %s\r\n", acl_last_serror());
			break;
		}
	}

	/* 關閉 UDP 套接字 */
	acl_vstream_close(stream);
}

 

      使用 acl 編寫的 UDP 客戶端示例如下:

static void udp_client(void)
{
	const char *local_addr = "127.0.0.1:1089";  /* 本客戶端綁定的地址 */
	const char *peer_addr = "127.0.0.1:1088";  /* 服務端綁定的地址 */
	int   i, ret, dlen;
	char  buf[1024], data[1024];
	ACL_VSTREAM *stream = acl_vstream_bind(local_addr, 2);  /* 綁定 UDP 套接口 */

	if (stream == NULL) {
		printf("acl_vstream_bind %s error %s\r\n",
			local_addr, acl_last_serror());
		return;
	}
	memset(data, 'X', sizeof(data);
	dlen = sizeof(data);
	
	for (i = 0; i < 100; i++) {
		/* 每次寫時需要設定服務端地址 */
		acl_vstream_set_peer(stream, peer_addr);

		/* 向服務端寫入數據包 */
		ret = acl_vstream_write(stream, data, dlen);
		if (ret == ACL_VSTREAM_EOF) {
			printf("acl_vtream_writen error %s\r\n",
				acl_last_serror());
			break;
		}

		/* 從服務端讀取數據 */
		ret = acl_vstream_read(stream, buf, sizeof(buf));
		if (ret == ACL_VSTREAM_EOF) {
			printf("acl_vstream_read error %s\r\n",
				acl_last_serror());
			break;
		}
	}

	/* 關閉客戶端 UDP 套接字 */
	acl_vstream_close(stream);
}

       由以上兩個例子可以看出,使用 acl 網絡庫編寫 UDP 程序也是非常簡單的,但有幾點需要注意:

      1、雖然 acl 網絡庫中的 UDP 功能也借用 ACL_VSTREAM 結構定義及 acl_vstream_xxx 等接口定義,但 UDP 傳輸依然是數據包式(即非流式),所以 acl 網絡庫中的有關 TCP 的使用方法在 UDP 中並不適合(如:acl_vstream_readn, acl_vstream_gets);

      2、UDP 傳輸不保證順序性及可靠性,所以 acl 網絡庫在綁定 UDP 端口時允許用戶指定讀超時時間;

      3、使用 acl 網絡庫編寫 UDP 客戶端時,在每次向服務端寫數據時,最好每次都先通過 acl_vstream_set_peer 設定服務端綁定地址。

 

      參考:

      acl 項目下載地址:https://sourceforge.net/projects/acl/

      svn:svn://svn.code.sf.net/p/acl/code/trunk acl-code

      github 地址:https://github.com/acl-dev/acl

      udp 服務端示例:acl\samples\udp_server

      udp 客戶端示例:acl\samples\udp_client

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