C++ 簡單Socket服務端程式碼實現
程式碼如下:
// Server.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <winsock2.h> #pragma comment(lib,"Ws2_32.lib") int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsaData; if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0) { printf("load socket version error!\n"); return 0; } SOCKET sockListen = socket(AF_INET,SOCK_STREAM,0); if (sockListen == INVALID_SOCKET) { printf("create socket error!\n"); return 0; } sockaddr_in srvAddr; srvAddr.sin_family = AF_INET; srvAddr.sin_port = htons(80); srvAddr.sin_addr.S_un.S_addr = INADDR_ANY; if (bind(sockListen,(sockaddr*)&srvAddr,sizeof(srvAddr)) == INVALID_SOCKET) { printf("bind error\n"); return 0; } if(listen(sockListen,10) == INVALID_SOCKET) { printf("listen error!\n"); return 0; } SOCKET sockMsg; sockaddr_in remoteAddr; int nLen = sizeof(remoteAddr); sockMsg = accept(sockListen,(sockaddr *)&remoteAddr,&nLen); if (sockMsg == INVALID_SOCKET) { printf("accept error!\n"); return 0; } char recvBuf[255]; memset(recvBuf,1,sizeof(recvBuf)); while (true) { recv(sockMsg,recvBuf,sizeof(recvBuf),0); printf("%s\n",recvBuf); const char* sendBuf = "hello Client!"; send(sockMsg,sendBuf,strlen(sendBuf),0); } closesocket(sockMsg); closesocket(sockListen); WSACleanup(); return 0; }
拆分解釋:
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
{
printf("load socket version error!\n");
return 0;
}
載入套接字版本庫。
WSADATA:用來儲存 WSAStartup 函式呼叫後返回的 Windows Sockets 資料;
WSAStartup 函式:WSA的啟用命令;
WSA:Windows Socket Asynchronous Windows非同步套接字
SOCKET sockListen = socket(AF_INET,SOCK_STREAM,0); if (sockListen == INVALID_SOCKET) { printf("create socket error!\n"); return 0; }
建立套接字。
SOCKET socket(int af, int type, int protocol);
int af: 指定地址族;
int type: 指定socket型別,常用SOCKET_STREAM,SOCK_DGRAM;
int protocol: 指定協議,為 0 時,自動選擇與第二個引數匹配的協議,一般預設為 0;
sockaddr_in srvAddr; srvAddr.sin_family = AF_INET; srvAddr.sin_port = htons(80); srvAddr.sin_addr.S_un.S_addr = INADDR_ANY; if (bind(sockListen,(sockaddr*)&srvAddr,sizeof(srvAddr)) == INVALID_SOCKET) { printf("bind error\n"); return 0; }
繫結 IP 和 埠。
int bind(SOCKET s, const struct sockaddr FAR* name, int namelen);
SOCKET s: 描述一個未繫結的套接字的描述符,即不可以重複繫結;
const struct sockaddr FAR* name: 從 sockaddr 結構中分配得到套接字的地址;
int namelen: name 引數中值的長度;
srvAddr.sin_family = AF_INET: 建立套接字時,用該欄位指定地址家族,對於 TCP/IP 協議,必須設定為 AF_INET ;
srvAddr.sin_port = htons(80): sin_port設定埠號;
srvAddr.sin_addr.S_un.S_addr = INADDR_ANY: 設定IP
if(listen(sockListen,10) == INVALID_SOCKET)
{
printf("listen error!\n");
return 0;
}
開啟監聽。
int listen(SOCKET s, int blacklog);
SOCKET s: 描述一個繫結的、沒有連線的套接字的描述符;
int blacklog: 等待連線的佇列的最大長度;
SOCKET sockMsg;
sockaddr_in remoteAddr;
int nLen = sizeof(remoteAddr);
sockMsg = accept(sockListen,(sockaddr *)&remoteAddr,&nLen);
if (sockMsg == INVALID_SOCKET)
{
printf("accept error!\n");
return 0;
}
資料接收。
SOCKET sockMsg: 通訊套接字;
sockaddr_in remoteAddr: 遠端連線地址;
SOCKET accept(_in SOCKET s, _out struct sockaddr* addr, _inout int *addrlen);
in SOCKET s: 描述一個套接字在監聽函式中被置於監聽狀態的描述符;
_out struct sockaddr* addr: 一個可選的指標,用來接收連線實體的地址;
_inout int *addrlen: 一個可選的指向一個整數的指標,它包含了 addr 引數所指向的結構的長度;
char recvBuf[255];
memset(recvBuf,1,sizeof(recvBuf));
while (true)
{
recv(sockMsg,recvBuf,sizeof(recvBuf),0);
printf("%s\n",recvBuf);
const char* sendBuf = "hello Client!";
send(sockMsg,sendBuf,strlen(sendBuf),0);
}
資料接收和傳送。
memset(): 此函式為新申請的記憶體做初始化工作;
int recv(SOCKET s, char FAR *buf, int len, int flags); 返回接收到的位元組數
SOCKET s: 連線套接字描述符;
char FAR *buf: 用於輸入資料的緩衝區;
int len: buf引數的長度;
int flags: 標記指定呼叫的方式,一般為 0;
int send(SOCKET s, char FAR *buf, int len, int flags);如果沒有發生錯誤,函式將返回傳送的位元組數
SOCKET s: 連線套接字描述符;
char FAR *buf: 包含要傳輸的資料的緩衝區;
int len: buf引數的長度;
int flags: 標記指定呼叫的方式,一般為 0;
closesocket(sockMsg);
closesocket(sockListen);
WSACleanup();
釋放資源。