diff --git a/libs/clipboard/src/cliprdr.rs b/libs/clipboard/src/cliprdr.rs
index 08d4021e8..f8d5d84b0 100644
--- a/libs/clipboard/src/cliprdr.rs
+++ b/libs/clipboard/src/cliprdr.rs
@@ -239,8 +239,6 @@ pub type CLIPRDR_FORMAT = _CLIPRDR_FORMAT;
 pub struct _CLIPRDR_FORMAT_LIST {
     pub connID: UINT32,
     pub msgType: UINT16,
-    pub msgFlags: UINT16,
-    pub dataLen: UINT32,
     pub numFormats: UINT32,
     pub formats: *mut CLIPRDR_FORMAT,
 }
diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs
index 7c6ccae0d..4d1632292 100644
--- a/libs/clipboard/src/lib.rs
+++ b/libs/clipboard/src/lib.rs
@@ -1,6 +1,6 @@
 use cliprdr::*;
 use hbb_common::{
-    log,
+    allow_err, log,
     tokio::sync::{
         mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
         Mutex as TokioMutex,
@@ -12,7 +12,7 @@ use std::{
     boxed::Box,
     collections::HashMap,
     ffi::{CStr, CString},
-    sync::Mutex,
+    sync::{Arc, Mutex, RwLock},
 };
 
 pub mod cliprdr;
@@ -20,25 +20,20 @@ pub mod cliprdr;
 #[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(tag = "t", content = "c")]
 pub enum ClipbaordFile {
-    ServerFormatList {
-        conn_id: i32,
+    FormatList {
         format_list: Vec<(i32, String)>,
     },
-    ServerFormatListResponse {
-        conn_id: i32,
+    FormatListResponse {
         msg_flags: i32,
     },
-    ServerFormatDataRequest {
-        conn_id: i32,
+    FormatDataRequest {
         requested_format_id: i32,
     },
-    ServerFormatDataResponse {
-        conn_id: i32,
+    FormatDataResponse {
         msg_flags: i32,
         format_data: Vec<u8>,
     },
     FileContentsRequest {
-        conn_id: i32,
         stream_id: i32,
         list_index: i32,
         dw_flags: i32,
@@ -49,7 +44,6 @@ pub enum ClipbaordFile {
         clip_data_id: i32,
     },
     FileContentsResponse {
-        conn_id: i32,
         msg_flags: i32,
         stream_id: i32,
         requested_data: Vec<u8>,
@@ -61,18 +55,76 @@ struct ConnEnabled {
     conn_enabled: HashMap<i32, bool>,
 }
 
-lazy_static::lazy_static! {
-    static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(i32, ClipbaordFile)>, TokioMutex<UnboundedReceiver<(i32, ClipbaordFile)>>) = {
-        let (tx, rx) = unbounded_channel();
-        (tx, TokioMutex::new(rx))
-    };
+struct MsgChannel {
+    peer_id: String,
+    conn_id: i32,
+    sender: UnboundedSender<ClipbaordFile>,
+    receiver: Arc<TokioMutex<UnboundedReceiver<ClipbaordFile>>>,
+}
 
+lazy_static::lazy_static! {
+    static ref VEC_MSG_CHANNEL: RwLock<Vec<MsgChannel>> = Default::default();
     static ref CLIP_CONN_ENABLED: Mutex<ConnEnabled> = Mutex::new(ConnEnabled::default());
 }
 
-#[inline(always)]
-pub fn get_rx_clip_client<'a>() -> &'a TokioMutex<UnboundedReceiver<(i32, ClipbaordFile)>> {
-    &MSG_CHANNEL_CLIENT.1
+#[inline]
+pub async fn get_rx_cliprdr_client<'a>(
+    peer_id: &str,
+) -> (i32, Arc<TokioMutex<UnboundedReceiver<ClipbaordFile>>>) {
+    let mut lock = VEC_MSG_CHANNEL.write().unwrap();
+    match lock.iter().find(|x| x.peer_id == peer_id.to_owned()) {
+        Some(msg_channel) => (msg_channel.conn_id, msg_channel.receiver.clone()),
+        None => {
+            let (sender, receiver) = unbounded_channel();
+            let receiver = Arc::new(TokioMutex::new(receiver));
+            let receiver2 = receiver.clone();
+            let conn_id = lock.len() as i32 + 1;
+            let msg_channel = MsgChannel {
+                peer_id: peer_id.to_owned(),
+                conn_id,
+                sender,
+                receiver,
+            };
+            lock.push(msg_channel);
+            (conn_id, receiver2)
+        }
+    }
+}
+
+#[inline]
+pub async fn get_rx_cliprdr_server<'a>(
+    conn_id: i32,
+) -> Arc<TokioMutex<UnboundedReceiver<ClipbaordFile>>> {
+    let mut lock = VEC_MSG_CHANNEL.write().unwrap();
+    match lock.iter().find(|x| x.conn_id == conn_id) {
+        Some(msg_channel) => msg_channel.receiver.clone(),
+        None => {
+            let (sender, receiver) = unbounded_channel();
+            let receiver = Arc::new(TokioMutex::new(receiver));
+            let receiver2 = receiver.clone();
+            let msg_channel = MsgChannel {
+                peer_id: "".to_owned(),
+                conn_id,
+                sender,
+                receiver,
+            };
+            lock.push(msg_channel);
+            receiver2
+        }
+    }
+}
+
+#[inline]
+fn send_data(conn_id: i32, data: ClipbaordFile) {
+    // no need to handle result here
+    if let Some(msg_channel) = VEC_MSG_CHANNEL
+        .read()
+        .unwrap()
+        .iter()
+        .find(|x| x.conn_id == conn_id)
+    {
+        allow_err!(msg_channel.sender.send(data));
+    }
 }
 
 pub fn set_conn_enabled(conn_id: i32, enabled: bool) {
@@ -88,61 +140,40 @@ pub fn empty_clipboard(context: &mut Box<CliprdrClientContext>, conn_id: i32) ->
 
 pub fn server_clip_file(
     context: &mut Box<CliprdrClientContext>,
-    s_conn_id: i32,
+    conn_id: i32,
     msg: ClipbaordFile,
 ) -> u32 {
     match msg {
-        ClipbaordFile::ServerFormatList {
-            mut conn_id,
-            format_list,
-        } => {
-            if s_conn_id != 0 {
-                conn_id = s_conn_id as i32;
-            }
+        ClipbaordFile::FormatList { format_list } => {
             log::debug!("server_format_list called");
             let ret = server_format_list(context, conn_id, format_list);
             log::debug!("server_format_list called, return {}", ret);
             ret
         }
-        ClipbaordFile::ServerFormatListResponse {
-            mut conn_id,
-            msg_flags,
-        } => {
-            if s_conn_id != 0 {
-                conn_id = s_conn_id as i32;
-            }
+        ClipbaordFile::FormatListResponse { msg_flags } => {
             log::debug!("format_list_response called");
             let ret = server_format_list_response(context, conn_id, msg_flags);
             log::debug!("server_format_list_response called, return {}", ret);
             ret
         }
-        ClipbaordFile::ServerFormatDataRequest {
-            mut conn_id,
+        ClipbaordFile::FormatDataRequest {
             requested_format_id,
         } => {
-            if s_conn_id != 0 {
-                conn_id = s_conn_id as i32;
-            }
             log::debug!("format_data_request called");
             let ret = server_format_data_request(context, conn_id, requested_format_id);
             log::debug!("server_format_data_request called, return {}", ret);
             ret
         }
-        ClipbaordFile::ServerFormatDataResponse {
-            mut conn_id,
+        ClipbaordFile::FormatDataResponse {
             msg_flags,
             format_data,
         } => {
-            if s_conn_id != 0 {
-                conn_id = s_conn_id as i32;
-            }
             log::debug!("format_data_response called");
             let ret = server_format_data_response(context, conn_id, msg_flags, format_data);
             log::debug!("server_format_data_response called, return {}", ret);
             ret
         }
         ClipbaordFile::FileContentsRequest {
-            mut conn_id,
             stream_id,
             list_index,
             dw_flags,
@@ -152,9 +183,6 @@ pub fn server_clip_file(
             have_clip_data_id,
             clip_data_id,
         } => {
-            if s_conn_id != 0 {
-                conn_id = s_conn_id as i32;
-            }
             log::debug!("file_contents_request called");
             let ret = server_file_contents_request(
                 context,
@@ -172,14 +200,10 @@ pub fn server_clip_file(
             ret
         }
         ClipbaordFile::FileContentsResponse {
-            mut conn_id,
             msg_flags,
             stream_id,
             requested_data,
         } => {
-            if s_conn_id != 0 {
-                conn_id = s_conn_id as i32;
-            }
             log::debug!("file_contents_response called");
             let ret = server_file_contents_response(
                 context,
@@ -225,8 +249,6 @@ pub fn server_format_list(
         let format_list = CLIPRDR_FORMAT_LIST {
             connID: conn_id as UINT32,
             msgType: 0 as UINT16,
-            msgFlags: 0 as UINT16,
-            dataLen: 0 as UINT32,
             numFormats: num_formats,
             formats: formats.as_mut_ptr(),
         };
@@ -243,6 +265,7 @@ pub fn server_format_list(
         ret as u32
     }
 }
+
 pub fn server_format_list_response(
     context: &mut Box<CliprdrClientContext>,
     conn_id: i32,
@@ -262,6 +285,7 @@ pub fn server_format_list_response(
         ret as u32
     }
 }
+
 pub fn server_format_data_request(
     context: &mut Box<CliprdrClientContext>,
     conn_id: i32,
@@ -280,6 +304,7 @@ pub fn server_format_data_request(
         ret as u32
     }
 }
+
 pub fn server_format_data_response(
     context: &mut Box<CliprdrClientContext>,
     conn_id: i32,
@@ -301,6 +326,7 @@ pub fn server_format_data_response(
         ret as u32
     }
 }
+
 pub fn server_file_contents_request(
     context: &mut Box<CliprdrClientContext>,
     conn_id: i32,
@@ -335,6 +361,7 @@ pub fn server_file_contents_request(
         ret as u32
     }
 }
+
 pub fn server_file_contents_response(
     context: &mut Box<CliprdrClientContext>,
     conn_id: i32,
@@ -398,7 +425,7 @@ extern "C" fn client_format_list(
 ) -> UINT {
     log::debug!("client_format_list called");
 
-    let conn_id;
+    // let conn_id;
     let mut format_list: Vec<(i32, String)> = Vec::new();
     unsafe {
         let mut i = 0u32;
@@ -420,14 +447,15 @@ extern "C" fn client_format_list(
             // log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name);
             i += 1;
         }
-        conn_id = (*clip_format_list).connID as i32;
+        // conn_id = (*clip_format_list).connID as i32;
     }
-    let data = ClipbaordFile::ServerFormatList {
-        conn_id,
-        format_list,
-    };
+    let data = ClipbaordFile::FormatList { format_list };
     // no need to handle result here
-    MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
+    VEC_MSG_CHANNEL
+        .read()
+        .unwrap()
+        .iter()
+        .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone())));
 
     0
 }
@@ -444,9 +472,8 @@ extern "C" fn client_format_list_response(
         conn_id = (*format_list_response).connID as i32;
         msg_flags = (*format_list_response).msgFlags as i32;
     }
-    let data = ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags };
-    // no need to handle result here
-    MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
+    let data = ClipbaordFile::FormatListResponse { msg_flags };
+    send_data(conn_id, data);
 
     0
 }
@@ -463,12 +490,11 @@ extern "C" fn client_format_data_request(
         conn_id = (*format_data_request).connID as i32;
         requested_format_id = (*format_data_request).requestedFormatId as i32;
     }
-    let data = ClipbaordFile::ServerFormatDataRequest {
-        conn_id,
+    let data = ClipbaordFile::FormatDataRequest {
         requested_format_id,
     };
     // no need to handle result here
-    MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
+    send_data(conn_id, data);
 
     0
 }
@@ -495,13 +521,11 @@ extern "C" fn client_format_data_response(
             .to_vec();
         }
     }
-    let data = ClipbaordFile::ServerFormatDataResponse {
-        conn_id,
+    let data = ClipbaordFile::FormatDataResponse {
         msg_flags,
         format_data,
     };
-    // no need to handle result here
-    MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
+    send_data(conn_id, data);
 
     0
 }
@@ -544,7 +568,6 @@ extern "C" fn client_file_contents_request(
     }
 
     let data = ClipbaordFile::FileContentsRequest {
-        conn_id,
         stream_id,
         list_index,
         dw_flags,
@@ -554,8 +577,7 @@ extern "C" fn client_file_contents_request(
         have_clip_data_id,
         clip_data_id,
     };
-    // no need to handle result here
-    MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
+    send_data(conn_id, data);
 
     0
 }
@@ -585,13 +607,11 @@ extern "C" fn client_file_contents_response(
         }
     }
     let data = ClipbaordFile::FileContentsResponse {
-        conn_id,
         msg_flags,
         stream_id,
         requested_data,
     };
-    // no need to handle result here
-    MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
+    send_data(conn_id, data);
 
     0
 }
diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c
index f55eeb718..58c7a301e 100644
--- a/libs/clipboard/src/windows/wf_cliprdr.c
+++ b/libs/clipboard/src/windows/wf_cliprdr.c
@@ -193,6 +193,7 @@ struct _CliprdrDataObject
 	ULONG m_nStreams;
 	IStream **m_pStream;
 	void *m_pData;
+	DWORD m_processID;
 	UINT32 m_connID;
 };
 typedef struct _CliprdrDataObject CliprdrDataObject;
@@ -246,7 +247,7 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr);
 BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr);
 BOOL wf_do_empty_cliprdr(wfClipboard *clipboard);
 
-static BOOL wf_create_file_obj(UINT32 connID, wfClipboard *cliprdrrdr, IDataObject **ppDataObject);
+static BOOL wf_create_file_obj(UINT32 *connID, wfClipboard *clipboard, IDataObject **ppDataObject);
 static void wf_destroy_file_obj(IDataObject *instance);
 static UINT32 get_remote_format_id(wfClipboard *clipboard, UINT32 local_format);
 static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UINT32 format);
@@ -673,6 +674,12 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO
 	if (!pFormatEtc || !pMedium || !instance)
 		return E_INVALIDARG;
 
+	// Not the same process id
+	if (instance->m_processID != GetCurrentProcessId())
+	{
+		return E_INVALIDARG;
+	}
+
 	clipboard = (wfClipboard *)instance->m_pData;
 	if (!clipboard->context->CheckEnabled(instance->m_connID))
 	{
@@ -892,6 +899,7 @@ static CliprdrDataObject *CliprdrDataObject_New(UINT32 connID, FORMATETC *fmtetc
 	instance->m_pData = data;
 	instance->m_nStreams = 0;
 	instance->m_pStream = NULL;
+	instance->m_processID = GetCurrentProcessId();
 	instance->m_connID = connID;
 
 	if (count > 0)
@@ -966,7 +974,7 @@ static BOOL wf_create_file_obj(UINT32 *connID, wfClipboard *clipboard, IDataObje
 	stgmeds[1].tymed = TYMED_ISTREAM;
 	stgmeds[1].pstm = NULL;
 	stgmeds[1].pUnkForRelease = NULL;
-	*ppDataObject = (IDataObject *)CliprdrDataObject_New(*connID, fmtetc, stgmeds, 2, clipboard);
+	*ppDataObject = (IDataObject *)CliprdrDataObject_New(*connID, *(connID + 1), fmtetc, stgmeds, 2, clipboard);
 	return (*ppDataObject) ? TRUE : FALSE;
 }
 
@@ -1669,7 +1677,8 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
 		DEBUG_CLIPRDR("info: WM_RENDERFORMAT");
 
 		// https://docs.microsoft.com/en-us/windows/win32/dataxchg/wm-renderformat?redirectedfrom=MSDN
-		if (cliprdr_send_data_request(0, 0, clipboard, (UINT32)wParam) != 0)
+		// to-do: ensure usage of 0
+		if (cliprdr_send_data_request(0, clipboard, (UINT32)wParam) != 0)
 		{
 			DEBUG_CLIPRDR("error: cliprdr_send_data_request failed.");
 			break;
diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto
index 4bb015866..aaa02c327 100644
--- a/libs/hbb_common/protos/message.proto
+++ b/libs/hbb_common/protos/message.proto
@@ -360,38 +360,31 @@ message FileDirCreate {
 
 // main logic from freeRDP
 message CliprdrMonitorReady {
-  int32 conn_id = 1;
 }
 
 message CliprdrFormat {
-  int32 conn_id = 1;
   int32 id = 2;
   string format = 3;
 }
 
 message CliprdrServerFormatList {
-  int32 conn_id = 1;
   repeated CliprdrFormat formats = 2;
 }
 
 message CliprdrServerFormatListResponse {
-  int32 conn_id = 1;
   int32 msg_flags = 2;
 }
 
 message CliprdrServerFormatDataRequest {
-  int32 conn_id = 1;
   int32 requested_format_id = 2;
 }
 
 message CliprdrServerFormatDataResponse {
-  int32 conn_id = 1;
   int32 msg_flags = 2;
   bytes format_data = 3;
 }
 
 message CliprdrFileContentsRequest {
-  int32 conn_id = 1;
   int32 stream_id = 2;
   int32 list_index = 3;
   int32 dw_flags = 4;
@@ -403,7 +396,6 @@ message CliprdrFileContentsRequest {
 }
 
 message CliprdrFileContentsResponse {
-  int32 conn_id = 1;
   int32 msg_flags = 3;
   int32 stream_id = 4;
   bytes requested_data = 5;