1. 程式人生 > >C++ 簡單Socket服務端程式碼實現

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();
釋放資源。