Socket編程基礎——面向鏈接TCP

WinSock是Windows環境下的網絡編程接口,它最初是基於Unix環境下的BSD Socket,是一個與網絡協議無關的編程接口。WinSock包含兩個主要版本,即WinSock1和WinSock2,在vs2010環境下,一般使用WinSock 2.2實現網絡通訊的功能。編程

一、Socket接口啓動
須要引入頭文件winsock2.h及庫文件ws2_32.lib服務器

#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
WSADATA wsadata;
if(WSAStartup(MAKEWORD(2,2),&wsadata)!=0)
{
    cout<<"Init error"<<endl;
    return -1;
}

WSAStartup函數原型以下:
int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData)
(1)wVersionRequested:Socket接口版本號,例如2.2版本(MAKEWORD(2,2)),高位字節存儲副版本號,低位字節存儲主版本號;
(2)lpWSAData:指向WSADATA結構體的指針,WSADATA結構體返回Socket信息;
若是上面函數執行成功,則返回0,不然能夠經過WSAGetLastError()查看錯誤代碼。例如:WSAEINVAL表示指定的Windows Socket版本不被該DLL支持。網絡

二、IP地址的表示形式
對普通用戶而言,IP地址使用點分法表示("192,168.0.1"字符串),但在計算機中不會使用這種方式,由於這樣會浪費存儲空間。實際上,計算機使用長整型存儲IP地址,分爲網絡字節序和主機字節序。
(1)網絡字節序
在網絡傳輸過程當中,IP地址保存爲32位二進制,TCP/IP規定,在低位存儲地址中保存數據的高位字節,這種存儲順序稱爲網絡字節順序,因此數據的傳輸由高位至低位進行的。不一樣網絡設備和操做系統在發送數據以前都須要將二進制數據轉爲網絡字節序。
(2)IP地址結構體
通用結構socket

struct sockaddr { 
unsigned short sa_family; 
char sa_data[14]; 
};

經常使用結構函數

struct sockaddr_in { 
short int sin_family; 
unsigned short int sin_port; 
struct in_addr sin_addr; 
unsigned char sin_zero[8]; 
};

struct in_addr就是32位IP地址。操作系統

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;
#define s_addr  S_un.S_addr
};

使用inet_addrinet_ntoa這兩個函數能夠實現點分IP地址字符串和網絡字節序IP地址之間的轉換。
unsigned long inet_addr(const char *cp):點分字符串->s_addr
char FAR * inet_ntoa(struct in_addr in)in_addr(sin_addr)->點分字符串指針

(3)主機字節序
可使用htonl(),htons(),ntohl(),ntohs()這四個函數來實現主機字節順序和網絡字節順序的轉換。code

三、服務器端通訊流程
(1)建立服務器套接字server

server=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

指定IP地址族、SOCKET類型,協議,返回SOCKET接口

(2)綁定本地端口、IP

sockaddr_in sAddr;
sAddr.sin_family=AF_INET;
sAddr.sin_port=htons(9000);
sAddr.sin_addr.S_un.S_addr=htonl(ADDR_ANY);
bind(server,(sockaddr*)&sAddr,sizeof(sAddr));

(3)監聽等待鏈接

listen(server,5);

(4)接收鏈接,返回Socket

sockaddr_in cAddr;
int len=sizeof(cAddr);
client=accept(server,(sockaddr*)&cAddr,&len);

(5)接收數據

ZeroMemory(buf,BUF_SIZE);
recv(client,buf,BUF_SIZE,0);

buf爲緩衝區,BUF_SIZE是緩衝區的大小;ZeroMemory函數將緩衝區置0,替代memset函數。

(6)發送數據
send(client,buf,strlen(buf),0);
在接收過程當中接收大小寫成緩衝區大小,發送時寫成發送的數據大小!

四、客戶端通訊流程
(1)建立客戶端套接字

client=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

(2)鏈接服務器

cAddr.sin_port=htons(9000);
cAddr.sin_family=AF_INET;
cAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
retVal=connect(client,(sockaddr*)&cAddr,sizeof(cAddr));

(3)發送數據/接收數據
同服務器端

五、清理
(1)shutdown禁止制定的Socket上發送和接收數據
int shutdown(SOCKET s,int how)
參數s表示要關閉的Socket,當參數how被設置爲SD_RECEIVE時,不容許再次調用recv接收數據,設置爲SD_SEND時,不容許再次調用send發送數據,設置爲SD_BOTH時,不容許發送和接受數據。
(2)closesocket
(3)WSACleanup

相關文章
相關標籤/搜索