winsock基础
1、Winsock初始化
int WSAStartup(WORD wVersionRequested ,LPWSADATA lpWSAData);
函數WSAStartup用于加載WinSock庫,
參數 wVersionRequested 用于指定要加載的庫的版本,高字節表示副版本號,低字節表示主版本號;可使用宏MAKEWORD(x,y)設置獲得,其中x表示高字節,y表示低字節。
參數lpWSAData是指向WSAData結構的指針,WSAStartup函數通過此參數將其加載的WinSock版本相關信息反饋給調用者,
struct WSAData
{
WORD wVersion; //表示打算使用的版本
WORD wHighVersion; //系統現在最高支持的版本
char szDescription[WSADESCRIPTION_LEN+1]; //由特定的WinSock實施方案設定,基本沒用
char szSystemStatus[WSASYS_STATUS_LEN+1]; //同上
unsigned short iMaxSockets; //假設同時最多打開多少套接字,不用使用,因為同時最多打開的套接字數目不是固定的,很大程度上跟物理內存的多少有關
unsigned short iMaxUdpDg; //數據包的最大長度,不用使用,數據報的最大長度應該使用WSAEnumProtocols獲得,
char FAR *lpVendorInfo; //為廠商預留的字段,
} WSADATA,FAR *LPWSADATA;
?
TCP編程
服務器端
1.建立socket套接字
2.bind將套接字綁定到指定的地址
int bind(SOCKET s,const struct sockaddr FAR* name,int namelen);//s等待客戶端連接的socket,name一個sockaddr緩沖區包含要使用的協議和地址相關信息,namelen緩沖區長度。
列:
SOCKET S;
struct sockaddr_in tcpaddr;
int port = 5150;
s = SOCKET(AF_INET,SOCK_STREAM,IPPROTO_TCP);
tcpaddr.sin_family = AF_INET;
tcpaddr.sin_port = htons(port);
tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s,(SOCKADDR *)&tcpaddr,sizeof(tcpaddr));
3.listen設置為偵聽模式
int listen(SOCKET s,int backlog);//s要限定的套接字,backlog指定正在等待的最大連接數
4.accept,WSAAccept偵聽端口,接受連接
SOCKET accept(
SOCKET s,
struct sockaddr FAR *addr,
int FAR *addrlen
);
SOCKET WSAAccept(
SOCKET s,
struct sockaddr FAR *addr,
LPINT addrlen,
LPCONDITIONPROC lpfnCondition,
DWORD dwCallbackData);
WSAAccept頭三個參數與accept相同,lpfnCondition參數是指向函數的一個指針,函數根據客戶請求來調用,函數決定是否接受用戶的連接請求
定義如下:
int CALLBACK ConditionFunc(
LPWSABUF lpCallerID,
LPWSABUF lpCallerData,
LPQOS lpSQOS,
LPQOS lpGQOS,
LPWSABUFF lpCalleeID,
LPWSABUFF lpCalleeData,
GROUP FAR *g,
DWORD dwCallbackData
)
客戶端
1.創建SOCKET
2.解析服務器名
3.用connect或WSAConnect初始化連接
int connect(SOCKET s,const struct? sockaddr FAR *name,int namelen);
int WSAConnect(SOCKET s,const struct sockaddr FAR *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS);
?
數據傳輸
1.發送數據:send和WSASend
int send(SOCKET s,const char FAR *buf,int len,int flags);
2.接受數據:recv和WSARecv
int? recv(SOCKET s,char FAR *buf,int len,int flags);
流協議
大多數面向連接的協議也是流協議,對于流協議套接字上收發數據不能保證對請求的數據量進行讀或寫,
如:char sendbuff[2048];
int nBytes = 2048;
ret = send(s,sendbuff,nBytes,0);
對send函數而言,可能發出的少于2048個字節,對于沒個收發數據的套接字來說,系統都為他們分配了相當充足的的緩沖區空間,在發送數據時,內部緩沖區一直保留到應該發到線上為止。幾種情況可導致這一情形發生:大量數據將緩沖區快速填滿,同時對TCP來說還有一個窗口大小的問題,接受端會對窗口大小進行調整,以指出他可以接受多少數據,這會使他在接受到一個新的大于0的窗口大小之前,不得在發送數據。必須將所以緩沖去的數據全都發送出去,可使用如下方式
char sendbuff[2048];
int nBytes = 2048;
int nLeft;
int idx;
nLeft = nByes;
idx = 0;
while(nLeft > 0)
{
ret = send(s,&sendbuff[idx],nLeft,0);
if (ret == SOCKET_ERROR)
{
//errr;
}
nLeft -= ret;
idx += ret;
}
中斷連接
1、從容關閉連接 shutdown
int shutdown(SOCKET s,int how);
2、closesocket
int closesocket(SOCKET s);
無連接協議(UDP):
1、接受端
int recvfrom(SOCKET s, char FAR *buf,int len, int flags,struct sockaddr FAR *from,int FAR *fromlen);
2、發送端
int sendto(SOCKET s,const char FAR *buf,int len,int flags,const struct sockaddr FAR *to,int FAR *tolen);
基于消息的協議
無連接協議大多都是基于消息的,對于面向連接的協議,協議本身提供了排序和邊界保護功能,而對于基于消息的對于寫入數據而言只能把它當作他的自治行為。對于接受端來說,必須提供充足的緩沖區,要不然,緩沖區不夠數據就會截斷丟失,被截斷的數據無法恢復,唯一的例外就是支持部分消息的協議
轉載于:https://www.cnblogs.com/liyunjin/archive/2010/08/29/1811785.html
總結
- 上一篇: (转)MVC模式参数传递的探究
- 下一篇: [Drupal] Submit and