socket1.1網絡編程

▲TCP與UDP
TCP模式:客戶端先向服務端發起連接請求,服務端接受連接請求後纔在客戶端與服務端建立連接,優點是連接雙方數據不易丟失。
UDP模式:通信雙方不需要建立連接就可向對方發送或接收數據,優點是實時性較高,缺點是數據可能會丟失。

 

▲網絡字節序
各種硬件對多字節數據的存儲順序不同,在起始地址處,有的機器先存入低位字節,而有的機器則先存入高位字節,如intel cpu將低位字節存入起始地址。在tcp/ip網絡協議中使用的16位和32位整數採用高位先存的規則。
將使用本地字節序的數據轉換成使用網絡字節序的數據
u_long htonl(u_long)                  //32位整數
u_short htons(u_short)             //16位整數

 

▲IPV4地址轉換
IPV4地址採用4字節表示地址,而人們通常使用點分十進制表示地址,如本機迴路地址127.0.0.1
u_long inet_addr(char*)      //將點分十進制地址字符串轉換爲4字節表示的網絡字節序地址
char* inet_ntoa(in_addr)     //將in_addr結構體中地址信息轉換爲點分十進制地址字符串

 

▲in_addr結構體
struct in_addr {
 union {
  struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
  struct { u_short s_w1,s_w2; } S_un_w;
  u_long S_addr;
 } S_un;
};
in_addr結構體用以表示ip地址信息,其內部是一個聯合變量S_un。
in_addr addr;
addr.S_un.S_addr=inet_addr("127.0.0.1");   //指定ip信息爲127.0.0.1
/////////////////////////////////////////
addr.S_un.S_addr=htonl(INADDR_ANY);    //指定ip信息爲本機獲得的任何ip地址

 

▲sockaddr與sockaddr_in結構體
struct sockaddr
{
  u_short sa_family;       //地址族,對於TCP/IP只能取AF_INET
  char sa_data[14];       //ip地址和端口信息
};


struct sockaddr_in
{
short sin_family;                //地址族,對於TCP/IP只能取AF_INET    
unsigned short sin_port;   //(網絡字節序)端口號,1024以下端口由系統保留
struct in_addr sin_addr;   //ip地址結構體
char sin_zero[8];              //填充數據
};

sockaddr與sockaddr_in結構體都包含有建立網絡連接所需的地址族、ip地址、端口號信息,然而sockaddr數據成員較籠統,因此多使用sockaddr_in結構體,在需要使用sockaddr數據處,可用sockaddr_in數據強制轉換爲sockaddr類型代替即可,sockaddr_in結構體會使用填充數據以使其位寬與sockaddr結構體位寬保持一致。

 

▲加載/卸載socket庫
WSADATA wsadata;       //WSADATA結構體變量
WSAStartup(MAKEWORD(1.1),&wsadata);    //加載socket庫
在MAKEWORD宏中指定要加載的socket庫版本,wsadata返回的信息中包含實際加載的庫版本和當前系統socket的最高版本。
WSACleanup();   /不再使用socket庫時應卸載socket庫,釋放資源

 

▲創建/關閉socket
SOCKET socket(int af,int type,int protocol)   //按指定的信息創建socket
af——地址族,對於TCP/IP協議只能去AF_INET
type——socket類型,SOCK_STREAM對應TCP,SOCK_DGRAM對應UDP
protocol——地址族相關協議,取0讓系統自行處理
closesocket(...)       //關閉socket,釋放資源

 

▲綁定IP地址與端口
bind(SOCKET s,const struct sockaddr FAR *name,int namelen) //將socket綁定到指定的ip地址與端口
s——未綁定的socket
name——sockaddr結構體指針,包含指定的地址族、ip地址和端口信息
namelen——sockaddr結構體大小

 

▲連接的監聽,發起,接受
listen(SOCKET s,int backlog)    //將socket設置爲監聽模式
s——已綁定,未連接的socket
backlog——請求隊列的長度,設爲SOMAXCONN時,由系統設置合理值。超出隊列長度的連接請求將被拒絕。
SOCKET accept(SOCKET s,struct sockaddr FAR *addr,int FAR *addrlen)  //接受連接請求
s——處於監聽狀態的socket
addr——sockaddr結構體指針,返回發起連接方的ip和端口信息
addrlen——sockaddr結構體長度,必須先賦初值
accept(...)會一直等待連接請求並暫停線程,接受連接後返回一個與對方連接的socket。
int connect(SOCKET s,const struct sockaddr FAR *name,int namelen)  //發起連接請求
s——未連接的socket
name——sockaddr結構體指針,指定向哪個ip與端口發起連接請求
namelen——sockaddr結構體大小
在發起連接請求時,線程會暫停,直到請求超時,或者對方接受連接,此時s成爲連接狀態的socket

 

▲發送/接收數據
TCP模式:
int send(SOCKET s,const char FAR *buf,int len,int flags)    //發送數據
s——已連接的socket
buf——待發送數據的地址
len——數據的大小
flags——發送方式,一般取0
send(...)返回發送的總字節數,可能比len指定的小。
int recv(SOCKET s,char FAR *buf,int len,int flags)   //接收數據
s——已連接的socket
buf——存放數據所用內存的地址
len——數據內存的大小
flags——接受方式,一般取0
recv(...)會一直等待數據接收並暫停線程,接收數據後返回接收數據的字節數。
///////////////////////////////////////////////////////////////////
UDP模式:
int sendto(SOCKET s,const char FAR *buf,int len,int flags,const struct sockaddr FAR *to,int tolen)   //發送數據
s——(可能處於連接態的)socket
buf——待發送數據的地址len——數據的大小
flags——發送方式,一般取0
to——sockaddr結構體指針,指定接收方ip地址與端口信息
tolen——sockaddr結構體大小
sendto(...)返回發送的總字節數,可能比len小。
int recvfrom(SOCKET s,char FAR* buf,int len,int flags,struct sockaddr FAR *from,int FAR *fromlen)   //接收數據
s——已綁定的socket
buf——存放數據所用內存的地址
len——數據內存的大小
flags——接收方式,一般取0
from——sockaddr結構體指針,存放發送方ip地址與端口信息
formlen——sockaddr結構體大小,必須賦初值
recvform(...)會一直等待數據接收並暫停線程,接收數據後返回接收數據的字節數。
-----------------------------------------------------------------------------------------------

▲基於TCP的服務器端程序(示例)

1.初始化

WSADATA wsadata;

WSAStartup(MAKEWORD(1,1),&wsadata);     //加載socket庫

SOCKET sersocket=socket(AF_INET,SOCK_STREAM,0);   //創建socket

2.將socket綁定到一個ip地址和端口上

sockaddr_in addrin;

addrin.sin_family=AF_INET;

addrin.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");   //服務器ip地址

addrin.sin_port=htons(1025);     //端口

bind(sersocket,(sockaddr*)&addrin,sizeof(sockaddr));    //綁定

3.監聽,等待並接受連接

listen(sersocket,1);       //監聽模式

sockaddr_in conaddr;

int len=sizeof(conaddr);

SOCKET consocket=accept(sersocket,(sockaddr*)&conaddr,&len);  //等待並接受連接

4.與連接的客戶端通信

char min[128]={0};

recv(consocket,min,128,0);   //接受數據

char mout[128]={...};

send(consocket,mout,strlen(mout),0);  //發送數據

5.釋放資源

closesocket(sersocket);   //關閉socket

WSACleanup();      //卸載socket庫

 

▲基於TCP的客戶端程序(示例)

1.初始化

WSADATA wsadata;

WSAStartup(MAKEWORD(1,1),&wsadata);       //加載socket庫

SOCKET clisocket=socket(AF_INET,SOCK_STREAM,0);   //創建socket

2.向服務器發送連接請求

sockaddr_in addrin;

addrin.sin_family=AF_INET;

addrin.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");   //服務器ip地址

addrin.sin_port=htons(1025);              //端口

connect(clisocket,(sockaddr*)&addrin,sizeof(sockaddr));   發起連接請求

3.與接受連接的服務器通信

char mout[128]={...};

char min[128]={0};

recv(clisocket,min,128,0);     //接收數據

send(clisocket,mout,strlen(mout)+1,0);   //發送數據

4.釋放資源

closesocket(clisocket);    //關閉socket

WSACleanup();        //卸載socket庫

 

▲基於UDP的服務器程序(示例)

1.初始化

WSADATA wsadata;

WSAStartup(MAKEWORD(1,1),&wsadata);     //加載socket庫

SOCKET socketser=socket(AF_INET,SOCK_DGRAM,0);    //創建socket

2.將socket綁定到一個ip地址和端口上

sockaddr_in addrin,addrincon;

addrin.sin_family=AF_INET;

addrin.sin_port=htons(2012);     //端口

addrin.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");    //服務器ip地址

bind(socketser,(sockaddr *)&addrin,sizeof(sockaddr));    //綁定

3.等待數據或發送數據

int len=sizeof(sockaddr);

char din[128]={0};

recvfrom(socketser,din,128,0,(sockaddr *)&addrincon,&len);   //接收數據

char dout[128]={...};

sendto(socketser,dout,strlen(dout)+1,0,(sockaddr *)&addrincon,len);   //發送數據

4.釋放資源

closesocket(socketser);    //關閉socket

WSACleanup();      //卸載socket庫

 

▲基於UDP的客戶端程序(示例)

1.初始化

WSADATA wsadata;

WSAStartup(MAKEWORD(1,1),&wsadata);     //加載socket庫

SOCKET socketcon=socket(AF_INET,SOCK_DGRAM,0);    //創建socket

2.發送數據或等待數據

sockaddr_in addrin,addrincon;

addrin.sin_family=AF_INET;

addrin.sin_port=htons(2012);      //端口

addrin.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");    //服務器ip地址

char dout[128]={...};

sendto(socketcon,dout,strlen(dout)+1,0,(sockaddr *)&addrin,sizeof(sockaddr));   //發送數據

char din[128]={0};

recvfrom(socketcon,din,128,0,(sockaddr *)&addrincon,&len);    //接收數據

3.釋放資源

closesocket(socketcon);    //關閉socket

WSACleanup();     //卸載socket庫


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