socket編程(1)簡單的TCP/UDP編程
socket編程是一種與底層網絡協議無關的編程方式,socket意味一種插口,即一個地址配上一個端口就構成了一端插口,既然他與底層協議無關,所以我們在使用socket 編程的時候,就可以任意選用哪種網絡協議,如最流行的tcp/ip協議。
在所有socket編程前腰包含頭文件<WinSock2.h>
服務器端:服務器端是指在tcp中進行監聽,也就是被動連接的那一端,服務器端在於客戶端建立好連接後,可以同服務器端發送和接收信息,他用一個監聽socket進行監聽客戶端連接,然後得到連接後可以創建一個通信socket進行通信,可以同時與多個客戶端通信,服務器端的編程主要有以下幾步:
1.初始winsocket
WSAStartup(MAKEWORD(2,2),&wsad);
2.建立一個用於監聽的socket
listenSocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
3.設定監聽socket的地址端口,並綁定給這個socket
listenAddr.sin_family=AF_INET;
listenAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
listenAddr.sin_port=htons(11111);
if(bind(listenSocket,(SOCKADDR *)(&listenAddr),sizeof(listenAddr))==SOCKET_ERROR){
abort();
return;
}
4.進行監聽
if(listen(listenSocket,1)==SOCKET_ERROR){
abort();
}
5.循環等待新連接進入的socket,如果等到則創建一個socket與之通信,accept操作是一個阻塞的操作。
while(!stopped){
acceptSocket=WSAAccept(listenSocket,(SOCKADDR*)(&clientAddr),&clientAddrSize,0,0);
if(acceptSocket==INVALID_SOCKET){
int code=WSAGetLastError();
break;
}
//這裏可以得到接入的socket的地址端口
char* add=inet_ntoa(clientAddr.sin_addr);
int port=ntohs(clientAddr.sin_port);
// acceptSocket就是一個已經於客戶端連接上的可以進行通信的socket,這裏 要 啟用一個 新線程用acceptSocket閾值通信
}
}
6、在啟用的新線程中一般是這樣的:
調用recv或send函數接收和發送信息
ret=recv(acceptSocket,buf,1000,0);
在線程結束前要關閉這個socket
closesocket(acceptSocket);
7關閉服務器
首先關閉監聽的socket
closesocket(listenSocket);
然後清理winsocket
WSACleanup();
**************************************************************************************
客戶端:客戶端socket是進行主動連接的那一方,客戶端的編程通常是這樣的:
1.初始winsocket
WSAStartup(MAKEWORD(2,2),&wsad);
2.建立一個用於連接的socket
csocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
3.設定監聽socket的地址端口,並綁定給這個socket
caddres.sin_family=AF_INET;
caddres.sin_addr.s_addr=inet_addr("127.0.0.1");
caddres.sin_port=htons(11111);
4、想某個服務器發送連接
if(WSAConnect(csocket,(SOCKADDR*)(&caddres),sizeof(caddres),0,0,0,0)==SOCKET_ERROR){
abort();
return;
}
5調用recv或send函數接收和發送信息
6通信結束後關閉
closesocket();
WSACleanup();
************************************************************************************
send和recv的一些方法:
send()函數不保證會把send的內容全部send出去,這樣就可能要多次send(),常用的方法是
int totalbyte=data.size();
DWORD ret;
WSABUF sendBuf;
sendBuf.len=totalbyte;
sendBuf.buf=data;
while(totalbyte>0){
if(WSASend(csocket,&sendBuf,1,&ret,0,0,0)==SOCKET_ERROR){
abort();
return;
}
totalbyte-=ret;
sendBuf.len=totalbyte;
sendBuf.buf+=ret;
}
*******************************************************************************************
下麵是基於無連接的UDP編程方法
這使用的是無連接的協議,TCP是有連接的,即要求在連接之前需要服務器端和客戶端都綁定端口,然後連接後可以雙向發送接收。
但是無連接的協議隻需要服務器端綁定端口,而客戶端不需要,客戶端隻需要向服務器端的監聽端口發送消息就可以了,也隻能由客戶端向服務器端發送消息。程序的實現如下;
服務器端
1.初始化
WSAStartup(MAKEWORD(2,2),&wsad);
2.創建用於監聽的socket
s=socket(AF_INET,SOCK_DGRAM,0);
3.綁定一個地址端口
SOCKADDR_IN udpAdress,sender;
int senferAddSize=sizeof(sender);
udpAdress.sin_family=AF_INET;
udpAdress.sin_port=htons(11112);
udpAdress.sin_addr.s_addr=inet_addr("127.0.0.1");
bind(s,(SOCKADDR*)&udpAdress,sizeof(udpAdress));
4.就可以調用recvfrom這個無連接的的接收函數接收數據,這個函數是阻塞的。無連接的協議不保證數據傳輸的可靠性,而且一次傳輸的數據量是有限的
ret=recvfrom(s,data,1000,0,(SOCKADDR*)&sender,&senferAddSize);
5.結束後關閉socket和清理
客戶端
1.初始化
WSAStartup(MAKEWORD(2,2),&wsad);
2.創建一個socket,但是不用綁定端口
usocket=socket(AF_INET,SOCK_DGRAM,0);
3.使用無連接的發送函數sendto向指定地址發送數據
sendto(usocket,data(),totalbyte,0,(SOCKADDR*)&dstAdd,dstAddrSize);
4.關閉、清理
closesocket(usocket);
WSACleanup();
最後更新:2017-04-02 06:51:36