1. 程式人生 > >Socket中send方法傳送結構體和recv接受結構體

Socket中send方法傳送結構體和recv接受結構體

  Socket中的send函式可以傳送字串,但不能直接傳送結構體,因此在傳送端先把結構體轉成字串,然後用send傳送,在接收端recv字串,再轉換成原先的結構體,這個就是解決問題的主要思路,實現中要注意的問題在下文闡述。

  為了客戶端之間能夠互相通訊,實現私聊,我採用伺服器轉發的方式,因此使用者傳送的每條訊息中除了訊息主體外,還必須包含有傳送者、接收者ID等資訊,如此採用結構體便是最佳的辦法了。我定義的結構體如下:

雙擊程式碼全選
1 2 3 4 5 6 7 struct send_info { char info_from[20]; //傳送者ID char info_to[20]; //接收者ID int info_length; //傳送的訊息主體的長度 char info_content[1024]; //訊息主體 };

  傳送端主要程式碼(為了簡潔說明問題,我把使用者輸入的內容、長度等驗證的程式碼去掉了):

雙擊程式碼全選
1 2 3 4 5 6 7 8 9 10 11 struct send_info info1; //定義結構體變數 printf("This is client,please input message:"); //從鍵盤讀取使用者輸入的資料,並寫入info1.info_content memset(info1.info_content,0,sizeof(info1.info_content));//清空快取 info1.info_length=read(STDIN_FILENO,info1.info_content,1024) - 1;//讀取使用者輸入的資料 memset(snd_buf,0,1024);//清空傳送快取,不清空的話可能導致接收時產生亂碼, //或者如果本次傳送的內容少於上次的話,snd_buf中會包含有上次的內容 memcpy(snd_buf,&info1,sizeof(info1)); //結構體轉換成字串 send(connect_fd,snd_buf,sizeof(snd_buf),0);//傳送資訊
接收端主要程式碼:
雙擊程式碼全選
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 struct send_info clt; //定義結構體變數 memset(recv_buf,'z',1024);//清空快取 recv(fd,recv_buf,1024,0 );//讀取資料 memset(&clt,0,sizeof(clt));//清空結構體 memcpy(&clt,recv_buf,sizeof(clt));//把接收到的資訊轉換成結構體 clt.info_content[clt.info_length]=''; //訊息內容結束,沒有這句的話,可能導致訊息亂碼或輸出異常 //有網友建議說傳遞的結構體中儘量不要有string型別的欄位,估計就是串尾符定位的問題 if(clt.info_content) //判斷接收內容並輸出 printf("nclt.info_from is %snclt.info_to is %snclt.info_content is%snclt.info_length is %dn",clt.info_from,clt.info_to,clt.info_content,clt.info_length); //至此,結構體的傳送與接收已經順利結束了

 c/c++通過socket傳送結構可以直接先將結構轉化到記憶體中,再通過send直接傳送。

  在網路通訊過程中往往涉及一些有關聯的引數傳遞,例如陣列,結構體之類的。對於結構體其實方法挺簡單,由於結構體物件在記憶體中分配的空間都是連續的,所以可以將整個結構體直接轉化成字串傳送,到了接收方再將這個字串還原成結構體就大功告成了。

  首先,我們建立一個結構體。

  struct UsrData{

  char usr_id[16];

  char usr_pwd[16];

  char usr_nickname[16];

  };

  當然,這個結構體在傳送方與接收方都必須宣告。

  接下來建立物件並初始化,然後傳送。

  UsrData sendUser;

  memcpy( sendUser.usr_id, “100001”, sizeof(“100001”) );

  memcpy( sendUser.usr_pwd, “123456”, sizeof(“123456”) );

  memcpy( sendUser.usr_nickname, “Rock”, sizeof(“Rock”) );

  send( m_socket, (char *)&sendUser, sizeof(UsrData), 0 );

  這樣傳送方就已經將這個mUser物件以字串的形式傳送出去了。

  最後在接收方做接收。

  char buffer[1024];

  UsrData recvUser;

  recv( m_socket, buffer, sizeof(buffer), 0 );

  memcpy( &recvUser, buffer, sizeof(buffer) );

  這樣得到的recvUser物件裡的資料與sendUser相同了。具體原因其實很簡單,就是因為結構體物件的記憶體區域連續,同時每個成員的區塊大小都分配好了,當接收完自己的區塊,其實自己的資料已經接收完成。挺簡單的,但還是挺有用的。 :smile:

      也可以直接將記憶體寫到檔案中:

      int cfg_fd = -1;
      cfg_fd = open(HD4100_CONFIG_FILE, O_RDWR|O_CREAT|O_TRUNC);
      if (cfg_fd < 0) 
      {
           printf("open config file failed/n");
           return -1;
      }
      write(cfg_fd, para, sizeof(hd4100_rec_t));  //hd4100_rec_t是自定義的結構
      close(cfg_fd); 
      printf("the para which is written to the config file:/n");


      read(cfg_fd, &hd4100_config, sizeof(hd4100_rec_t)); //從檔案讀內容到記憶體中
      close(cfg_fd);

       包含引用型別或值型別的結構或物件無法通過以上方法直接傳送,而必須通過序列化的方式轉化為二進位制流傳送和接收。如c# Socket傳送序列化Struct示例:

傳資料,下面給一個傳送struct的例子. 
首先:把struct寫到一個單獨的類中.編譯成dll 
using System; 
[Serializable] 
public struct USER_INF 

public long id; 
public string nickname; 
public string ***; 
public int age; 
public string address; 
public string password; 

然後在你的伺服器端和客戶端都新增這個dll. 
下面是伺服器端傳送這個序列化的struct 
while(true) 

Socket s=tcpl.AcceptSocket(); 
BinaryFormatter bf; 
bf = new BinaryFormatter(); 
MemoryStream stream = new MemoryStream(); 
USER_INF user; 
user.id=0; 
user.nickname="Pony"; 
user.***="?"; 
user.age=20; 
user.address="192.168.7.91"; 
user.password="123456"; 
bf.Serialize(stream,user); 
byte[] buff = stream.ToArray(); 
s.Send(buff,buff.Length,0); 
s.Close(); 
Console.WriteLine("?????!"); 


一下是client端接收到資料後反序列化 
BinaryFormatter bf; 
bf = new BinaryFormatter(); 
USER_INF user=(USER_INF)bf.Deserialize(s);

相關推薦

Socketsend方法傳送結構recv接受結構

  Socket中的send函式可以傳送字串,但不能直接傳送結構體,因此在傳送端先把結構體轉成字串,然後用send傳送,在接收端recv字串,再轉換成原先的結構體,這個就是解決問題的主要思路,實現中要注意的問題在下文闡述。   為了客戶端之間能夠互相通訊,實現私聊

SOCKETsendrecv函式工作原理與注意點

send函式工作原理:  send函式只負責將資料提交給協議層。 當呼叫該函式時,send先比較待發送資料的長度len和套接字s的傳送緩衝區的長度,如果len大於s的傳送緩衝區的長度,該函式返回SO

socketsendrecv函式的阻塞理解

int send( SOCKET s, const char FAR *buf, int len, int flags ); 不論是客戶還是伺服器應用程式都用send函式來向TCP連線的另一端傳送資料。客戶程式一般用send函式向伺服器傳送請求,而伺服器則通常用send函式來向客戶程式傳送應答。 該函式的

Socketsend()函式recv()函式詳解

1、send函式 int send( SOCKET s, const char FAR *buf, int len, int flags ); 不論是客戶還是伺服器應用程式都用send函式來向TCP連線的另一端傳送資料。 客戶程式一般用send函式向伺服器傳送請求,而伺

很簡單的在Ubuntu系統下安裝字切換默認字方法

拷貝 true 桌面 技術 系統 美麗 des net 加粗 摘要: Ubuntu系統安裝好後,默認字體對於中文的支持看上去不太美麗,於是很多朋友可能需要設置系統的默認字體為自己喜歡的字體。本文主要介紹如何解決這兩個問題。 說明:測試系統是Ubuntu14.04。

資料結構---棧佇列(結構實現)

棧(LIFO) 棧(stack)是一種只能在一端進行插入或刪除操作的線性表。 棧頂(top):允許進行插入、刪除操作的一端 棧底(bottom):另一端稱為棧底 進棧或入棧(push):插入操作 出棧或退棧(pop):棧的刪除操作 n個不同元素通過一個棧產生的出棧

spring框架工廠方法的創建銷毀

color this alt ima 實現 close col out err 1.編寫接口UserSerivce: public interface UserService { public void sayHello(); } 2.編寫實實現接口的方法,在

Android-LayoutInflaterinflate方法兩個引數三個引數的區別

關於inflate引數問題,我想很多人多多少少都瞭解一點,網上也有很多關於這方面介紹的文章,但是枯燥的理論或者翻譯讓很多小夥伴看完之後還是一臉懵逼,so,我今天想通過三個案例來讓小夥伴徹底的搞清楚這個東東。本篇部落格我們不講原始碼,只看使用。原始碼的解讀會在下一篇博文中帶

三個案例帶你看懂LayoutInflaterinflate方法兩個引數三個引數的區別

關於inflate引數問題,我想很多人多多少少都瞭解一點,網上也有很多關於這方面介紹的文章,但是枯燥的理論或者翻譯讓很多小夥伴看完之後還是一臉懵逼,so,我今天想通過三個案例來讓小夥伴徹底的搞清楚這個東東。本篇部落格我們不講原始碼,只看使用。原始碼的解讀會在下一篇博文中帶來。

socketsend傳送緩衝區大小的關係

自己做了個測試,伺服器只起socket在偵聽,不recv, 也不send. //ubuntu10.04 32bit #include <stdio.h> #include <sys/types.h> #include <sys/socke

jquery.on()方法指定子元素不指定子元素的區別

首先來看下這兩種情況下的輸出: <div class="parent"> <div class="father"> <div class="son">測試.on()方法</div>

Javaclone方法以及深複製淺複製

Java中處理基本資料型別(如:int , char , double等),都是採用按值傳遞的方式執行,除此之外的其他型別都是按照引用傳遞(傳遞的是一個物件的引用)的方式執行。物件在函式呼叫時和使用“=”賦值時都是引用傳遞。 Java中clone方法的作用是為了在現實程式

jqeach方法的退出迴圈結束本次迴圈

Query中each類似於javascript的for迴圈 但不同於for迴圈的是在each裡面不能使用break結束迴圈,也不能使用continue來結束本次迴圈,想要實現類似的功能就只能用return,break           用return falsecontin

路由器刷opwenwrt韌原廠韌教程

本文所用的路由器型號為:linksys wrt1900ac v2(第一次寫部落格,竟然發現CSDN的部落格不能快速插入圖片,差評) 環境準備 網線插入路由器的網線介面,然後再由路由器的LAN介面

H264碼流結構分析rtp打包結構詳解

網路抽象層單元型別 (NALU): NALU頭由一個位元組組成,它的語法如下:       +---------------+       |0|1|2|3|4|5|6|7|       +-+-+-+-+-+-+-+-+       |F|NRI|  Type   |       +---------

C語言結構以及在結構呼叫方法;聯合體聯合體的使用

#include <stdio.h>  #include<stdlib.h>void study(){}; struct student{ int age; int number; void(*study1)(); } main(){//使用,在結構

淺談c++結構共用的區別

ont 基本類型 erl list 變量名 ext 使用結構體 oot 數據格式 在c++中,結構體(struct)和共用體(union)是兩種很相似的復合數據類型,都可以用來存儲多種數據類型,但是兩者還有很大的區別。 結構體(struct) 結構是用戶自定

結構方法

pan att div println sel res bug com .com 結構體和方法 use std::fmt; #[derive(Debug)] struct Rectangle { width: u32, height: u32, }

C#將結構指針互轉的方法

緩沖 style system RR 程序集 ascii 通知 work Coding 1. 功能及位置 將數據從托管對象封送到非托管內存塊,屬於.NET Framework 類庫 命名空間:System.Runtime.InteropServices

結構連結串列陣列指標不同表達形式

int getMaxLengthOfItems(MEC_MENU *menu,int count){     int i;     int maxLen = strlen(menu[0].item);     for(i = 0; i < c