Socket中的send函數(shù)可以發(fā)送字符串,但不能直接發(fā)送結(jié)構(gòu)體,,因此在發(fā)送端先把結(jié)構(gòu)體轉(zhuǎn)成字符串,,然后用send發(fā)送,在接收端recv字符串,,再轉(zhuǎn)換成原先的結(jié)構(gòu)體,這個(gè)就是解決問題的主要思路,,實(shí)現(xiàn)中要注意的問題在下文闡述,。
為了客戶端之間能夠互相通信,實(shí)現(xiàn)私聊,,我采用服務(wù)器轉(zhuǎn)發(fā)的方式,,因此用戶發(fā)送的每條消息中除了消息主體外,還必須包含有發(fā)送者,、接收者ID等信息,,如此采用結(jié)構(gòu)體便是最佳的辦法了,。我定義的結(jié)構(gòu)體如下:
1 2 3 4 5 6 7 | struct send_info { char info_from[20]; //發(fā)送者ID char info_to[20]; //接收者ID int info_length; //發(fā)送的消息主體的長度 char info_content[1024]; //消息主體 }; |
發(fā)送端主要代碼(為了簡潔說明問題,我把用戶輸入的內(nèi)容,、長度等驗(yàn)證的代碼去掉了):
1 2 3 4 5 6 7 8 9 10 11 | struct send_info info1; //定義結(jié)構(gòu)體變量 printf("This is client,please input message:"); //從鍵盤讀取用戶輸入的數(shù)據(jù),,并寫入info1.info_content memset(info1.info_content,0,sizeof(info1.info_content));//清空緩存 info1.info_length=read(STDIN_FILENO,info1.info_content,1024) - 1;//讀取用戶輸入的數(shù)據(jù) memset(snd_buf,0,1024);//清空發(fā)送緩存,不清空的話可能導(dǎo)致接收時(shí)產(chǎn)生亂碼,, //或者如果本次發(fā)送的內(nèi)容少于上次的話,,snd_buf中會(huì)包含有上次的內(nèi)容 memcpy(snd_buf,&info1,sizeof(info1)); //結(jié)構(gòu)體轉(zhuǎn)換成字符串 send(connect_fd,snd_buf,sizeof(snd_buf),0);//發(fā)送信息 |
接收端主要代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | struct send_info clt; //定義結(jié)構(gòu)體變量 memset(recv_buf,'z',1024);//清空緩存 recv(fd,recv_buf,1024,0 );//讀取數(shù)據(jù) memset(&clt,0,sizeof(clt));//清空結(jié)構(gòu)體 memcpy(&clt,recv_buf,sizeof(clt));//把接收到的信息轉(zhuǎn)換成結(jié)構(gòu)體 clt.info_content[clt.info_length]=''; //消息內(nèi)容結(jié)束,沒有這句的話,,可能導(dǎo)致消息亂碼或輸出異常 //有網(wǎng)友建議說傳遞的結(jié)構(gòu)體中盡量不要有string類型的字段,,估計(jì)就是串尾符定位的問題 if(clt.info_content) //判斷接收內(nèi)容并輸出 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); //至此,結(jié)構(gòu)體的發(fā)送與接收已經(jīng)順利結(jié)束了 |
c/c++通過socket發(fā)送結(jié)構(gòu)可以直接先將結(jié)構(gòu)轉(zhuǎn)化到內(nèi)存中,,再通過send直接發(fā)送,。
在網(wǎng)絡(luò)通訊過程中往往涉及一些有關(guān)聯(lián)的參數(shù)傳遞,例如數(shù)組,,結(jié)構(gòu)體之類的,。對(duì)于結(jié)構(gòu)體其實(shí)方法挺簡單,由于結(jié)構(gòu)體對(duì)象在內(nèi)存中分配的空間都是連續(xù)的,,所以可以將整個(gè)結(jié)構(gòu)體直接轉(zhuǎn)化成字符串發(fā)送,,到了接收方再將這個(gè)字符串還原成結(jié)構(gòu)體就大功告成了。
首先,,我們建立一個(gè)結(jié)構(gòu)體,。
struct UsrData{
char usr_id[16];
char usr_pwd[16];
char usr_nickname[16];
};
當(dāng)然,這個(gè)結(jié)構(gòu)體在發(fā)送方與接收方都必須聲明,。
接下來創(chuàng)建對(duì)象并初始化,,然后發(fā)送。
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 );
這樣發(fā)送方就已經(jīng)將這個(gè)mUser對(duì)象以字符串的形式發(fā)送出去了,。
最后在接收方做接收,。
char buffer[1024];
UsrData recvUser;
recv( m_socket, buffer, sizeof(buffer), 0 );
memcpy( &recvUser, buffer, sizeof(buffer) );
這樣得到的recvUser對(duì)象里的數(shù)據(jù)與sendUser相同了。具體原因其實(shí)很簡單,,就是因?yàn)榻Y(jié)構(gòu)體對(duì)象的內(nèi)存區(qū)域連續(xù),,同時(shí)每個(gè)成員的區(qū)塊大小都分配好了,當(dāng)接收完自己的區(qū)塊,,其實(shí)自己的數(shù)據(jù)已經(jīng)接收完成,。挺簡單的,但還是挺有用的,。
也可以直接將內(nèi)存寫到文件中:
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是自定義的結(jié)構(gòu)
close(cfg_fd);
printf("the para which is written to the config file:/n");
read(cfg_fd, &hd4100_config, sizeof(hd4100_rec_t)); //從文件讀內(nèi)容到內(nèi)存中
close(cfg_fd);
包含引用類型或值類型的結(jié)構(gòu)或?qū)ο鬅o法通過以上方法直接發(fā)送,,而必須通過序列化的方式轉(zhuǎn)化為二進(jìn)制流發(fā)送和接收。如c# Socket傳送序列化Struct示例:
傳數(shù)據(jù),下面給一個(gè)傳送struct的例子.
首先:把struct寫到一個(gè)單獨(dú)的類中.編譯成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;
}
然后在你的服務(wù)器端和客戶端都添加這個(gè)dll.
下面是服務(wù)器端發(fā)送這個(gè)序列化的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端接收到數(shù)據(jù)后反序列化
BinaryFormatter bf;
bf = new BinaryFormatter();
USER_INF user=(USER_INF)bf.Deserialize(s);
Socket中的send函數(shù)可以發(fā)送字符串,,但不能直接發(fā)送結(jié)構(gòu)體,,因此在發(fā)送端先把結(jié)構(gòu)體轉(zhuǎn)成字符串,,然后用send發(fā)送,在接收端recv字符串,,再轉(zhuǎn)換成原先的結(jié)構(gòu)體,,這個(gè)就是解決問題的主要思路,實(shí)現(xiàn)中要注意的問題在下文闡述,。
為了客戶端之間能夠互相通信,,實(shí)現(xiàn)私聊,我采用服務(wù)器轉(zhuǎn)發(fā)的方式,,因此用戶發(fā)送的每條消息中除了消息主體外,,還必須包含有發(fā)送者、接收者ID等信息,,如此采用結(jié)構(gòu)體便是最佳的辦法了,。我定義的結(jié)構(gòu)體如下:
1 2 3 4 5 6 7 | struct send_info { char info_from[20]; //發(fā)送者ID char info_to[20]; //接收者ID int info_length; //發(fā)送的消息主體的長度 char info_content[1024]; //消息主體 }; |
發(fā)送端主要代碼(為了簡潔說明問題,我把用戶輸入的內(nèi)容,、長度等驗(yàn)證的代碼去掉了):
1 2 3 4 5 6 7 8 9 10 11 | struct send_info info1; //定義結(jié)構(gòu)體變量 printf("This is client,please input message:"); //從鍵盤讀取用戶輸入的數(shù)據(jù),,并寫入info1.info_content memset(info1.info_content,0,sizeof(info1.info_content));//清空緩存 info1.info_length=read(STDIN_FILENO,info1.info_content,1024) - 1;//讀取用戶輸入的數(shù)據(jù) memset(snd_buf,0,1024);//清空發(fā)送緩存,不清空的話可能導(dǎo)致接收時(shí)產(chǎn)生亂碼,, //或者如果本次發(fā)送的內(nèi)容少于上次的話,,snd_buf中會(huì)包含有上次的內(nèi)容 memcpy(snd_buf,&info1,sizeof(info1)); //結(jié)構(gòu)體轉(zhuǎn)換成字符串 send(connect_fd,snd_buf,sizeof(snd_buf),0);//發(fā)送信息 |
接收端主要代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | struct send_info clt; //定義結(jié)構(gòu)體變量 memset(recv_buf,'z',1024);//清空緩存 recv(fd,recv_buf,1024,0 );//讀取數(shù)據(jù) memset(&clt,0,sizeof(clt));//清空結(jié)構(gòu)體 memcpy(&clt,recv_buf,sizeof(clt));//把接收到的信息轉(zhuǎn)換成結(jié)構(gòu)體 clt.info_content[clt.info_length]=''; //消息內(nèi)容結(jié)束,沒有這句的話,,可能導(dǎo)致消息亂碼或輸出異常 //有網(wǎng)友建議說傳遞的結(jié)構(gòu)體中盡量不要有string類型的字段,,估計(jì)就是串尾符定位的問題 if(clt.info_content) //判斷接收內(nèi)容并輸出 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); //至此,結(jié)構(gòu)體的發(fā)送與接收已經(jīng)順利結(jié)束了 |
c/c++通過socket發(fā)送結(jié)構(gòu)可以直接先將結(jié)構(gòu)轉(zhuǎn)化到內(nèi)存中,,再通過send直接發(fā)送,。
在網(wǎng)絡(luò)通訊過程中往往涉及一些有關(guān)聯(lián)的參數(shù)傳遞,例如數(shù)組,,結(jié)構(gòu)體之類的,。對(duì)于結(jié)構(gòu)體其實(shí)方法挺簡單,由于結(jié)構(gòu)體對(duì)象在內(nèi)存中分配的空間都是連續(xù)的,,所以可以將整個(gè)結(jié)構(gòu)體直接轉(zhuǎn)化成字符串發(fā)送,,到了接收方再將這個(gè)字符串還原成結(jié)構(gòu)體就大功告成了。
首先,,我們建立一個(gè)結(jié)構(gòu)體,。
struct UsrData{
char usr_id[16];
char usr_pwd[16];
char usr_nickname[16];
};
當(dāng)然,這個(gè)結(jié)構(gòu)體在發(fā)送方與接收方都必須聲明,。
接下來創(chuàng)建對(duì)象并初始化,然后發(fā)送,。
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 );
這樣發(fā)送方就已經(jīng)將這個(gè)mUser對(duì)象以字符串的形式發(fā)送出去了,。
最后在接收方做接收,。
char buffer[1024];
UsrData recvUser;
recv( m_socket, buffer, sizeof(buffer), 0 );
memcpy( &recvUser, buffer, sizeof(buffer) );
這樣得到的recvUser對(duì)象里的數(shù)據(jù)與sendUser相同了。具體原因其實(shí)很簡單,,就是因?yàn)榻Y(jié)構(gòu)體對(duì)象的內(nèi)存區(qū)域連續(xù),,同時(shí)每個(gè)成員的區(qū)塊大小都分配好了,當(dāng)接收完自己的區(qū)塊,,其實(shí)自己的數(shù)據(jù)已經(jīng)接收完成,。挺簡單的,但還是挺有用的,。
也可以直接將內(nèi)存寫到文件中:
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是自定義的結(jié)構(gòu)
close(cfg_fd);
printf("the para which is written to the config file:/n");
read(cfg_fd, &hd4100_config, sizeof(hd4100_rec_t)); //從文件讀內(nèi)容到內(nèi)存中
close(cfg_fd);
包含引用類型或值類型的結(jié)構(gòu)或?qū)ο鬅o法通過以上方法直接發(fā)送,,而必須通過序列化的方式轉(zhuǎn)化為二進(jìn)制流發(fā)送和接收。如c# Socket傳送序列化Struct示例:
傳數(shù)據(jù),下面給一個(gè)傳送struct的例子.
首先:把struct寫到一個(gè)單獨(dú)的類中.編譯成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;
}
然后在你的服務(wù)器端和客戶端都添加這個(gè)dll.
下面是服務(wù)器端發(fā)送這個(gè)序列化的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端接收到數(shù)據(jù)后反序列化
BinaryFormatter bf;
bf = new BinaryFormatter();
USER_INF user=(USER_INF)bf.Deserialize(s);