[C++] Windows下的socket編程(這是一個簡單的TCP/IP例子)


Socket的概念:

Socket,即套接字,用於描述地址和端口,是一個通信鏈的句柄。

應用程序通過Socket像網絡發出請求或者回應。


什么事客戶/服務器模式:

在TCP/IP網絡應用中,通信的兩個進程相互作用的主要模式是客戶/服務器模式,即客戶端向服務器發出請求,服務器接收請求后,提供相應的服務。客戶/服務器模式的建立基於以下兩點:

1:建立網絡的起因是網絡中軟硬件資源、運算能力和信息不均等,需要共享,從而造就擁有眾多資源的主機提供服務,資源較少的客戶請求服務這一非對等作用

2:網間進程通信完全是異步的,相互通信的進程間既不存在父子關系,又不共享內存緩沖區

因此需要一種機制為希望通信的進程間建立聯系,為二者的數據交換提供同步,這就是基於客戶/服務端模式的TCP/IP

(這部分內容摘自socket編程原理)


需要做什么:

客戶端:建立Socket,通過端口號和地址確定目標服務器,使用Connect連接到服務器,send發送消息,等待處理,通信完成后調用CloseSocket關閉Socket

服務端:建立Socket,聲明自身的端口號和地址並綁定到Socket,使用Listen打開監聽,然后不斷用Accept去查看是否有連接,如果有,捕獲Socket,並通過Recv獲取消息的內容,通信完成后調用CloseSocket關閉這個對應Accept到的Socket,如果不再需要等待任何客戶端連接,那么用CloseSocket關閉掉自身的Socket

 

代碼示例

客戶端:這里創建一個CLientNet類,用於表示一個客戶

 

#pragma once

/*
ClinetNet.h:
用於表示一個客戶的網絡操作
*/

#include <stdio.h>
#include<windows.h>

#pragma comment(lib, "Ws2_32.lib")

class CClientNet
{
public:
	//連接上指定服務器
	int Connect(int port,const char* address);
	//發送信息
	int SendMsg(const char* msg,int len);
	//關閉
	void Close();

private:
	SOCKET m_sock;
};

 

/*
CLientNet.cpp
*/
#include "ClientNet.h"


int CClientNet::Connect( int port,const char* address )
{
	int rlt = 0;

	//用於記錄錯誤信息並輸出
	int iErrMsg;
	//啟動WinSock
	WSAData wsaData;
	iErrMsg = WSAStartup(MAKEWORD(1,1),&wsaData);
	if (iErrMsg != NO_ERROR)
		//有錯誤
	{
		printf("failed with wsaStartup error : %d\n",iErrMsg);

		rlt = 1;
		return rlt;
	}

	//創建Socket
	m_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if (m_sock == INVALID_SOCKET)
		//創建Socket失敗
	{
		printf("socket failed with error : %d\n",WSAGetLastError());

		rlt = 2;
		return rlt;
	}

	//目標服務器數據
	sockaddr_in sockaddrServer;
	sockaddrServer.sin_family = AF_INET;
	sockaddrServer.sin_port = port;
	sockaddrServer.sin_addr.s_addr = inet_addr(address);

	//連接,sock與目標服務器連接
	iErrMsg = connect(m_sock,(sockaddr*)&sockaddrServer,sizeof(sockaddrServer));
	if (iErrMsg < 0)
	{
		printf("connect failed with error : %d\n",iErrMsg);

		rlt = 3;
		return rlt;
	}

	return rlt;
}




int CClientNet::SendMsg(const char* msg,int len)
{
	int rlt = 0;

	int iErrMsg = 0;

	//發送消息,指定sock發送消息
	iErrMsg = send(m_sock,msg,len,0);
	if (iErrMsg < 0)
		//發送失敗
	{
		printf("send msg failed with error : %d\n",iErrMsg);

		rlt = 1;
		return rlt;
	}

	return rlt;
}

void CClientNet::Close()
{
	closesocket(m_sock);
}

 

#include "ClientNet.h"

void main()
{
	CClientNet client;
	
	//連接到127.0.0.1(即本地),端口號為8888的服務端
	printf("Connect\n");
	client.Connect(8888,"127.0.0.1");
	
	//發送消息
	printf("send msg\n");
	client.SendMsg("hello\0",sizeof("hello\0"));
	
	//關閉socket
	printf("close\n");
	client.Close();

	system("pause");
}


 

服務端代碼:

 

#pragma once

/*
ServerNet.h
用於表示服務端的網絡操作

*/

#include <stdio.h>
#include <winsock.h>

#pragma comment (lib,"ws2_32.lib")

class CServerNet
{
public:

	//初始化服務器,返回0表示成功
	int Init(const char* address,int port);

	//更新數據
	void Run();


private:
	SOCKET m_sock;
};

 

/*
ServerNet.cpp
*/
#include "ServerNet.h"

int CServerNet::Init( const char* address,int port )
{
	int rlt = 0;

	//用於記錄錯誤信息,並輸出
	int iErrorMsg;

	//初始化WinSock
	WSAData wsaData;
	iErrorMsg = WSAStartup(MAKEWORD(1,1),&wsaData);
	
	if (iErrorMsg != NO_ERROR)
	{
		//初始化WinSock失敗
		printf("wsastartup failed with error : %d\n",iErrorMsg);

		rlt = 1;
		return rlt;
	}

	//創建服務端Socket
	m_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if (m_sock == INVALID_SOCKET)
		
	{
		//創建Socket異常
		printf("socket failed with error : %d\n",WSAGetLastError());

		rlt = 2;
		return rlt;
	}

	//聲明信息
	sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = port;
	serverAddr.sin_addr.s_addr = inet_addr(address);

	//綁定
	iErrorMsg = bind(m_sock,(sockaddr*)&serverAddr,sizeof(serverAddr));
	if (iErrorMsg < 0)
	{
		//綁定失敗
		printf("bind failed with error : %d\n",iErrorMsg);
		rlt = 3;
		return rlt;
	}

	

	return rlt;
}

void CServerNet::Run()
{
	//公開連接
	listen(m_sock,5);

	sockaddr_in tcpAddr;
	int len = sizeof(sockaddr);
	SOCKET newSocket;
	char buf[1024];
	int rval;

	do 
	{
		//接收信息
		newSocket = accept(m_sock,(sockaddr*)&tcpAddr,&len);

		
		if (newSocket == INVALID_SOCKET)
		{
			//非可用socket

		}
		else
		{
			//新socket連接
			printf("new socket connect : %d\n",newSocket);


			//消息處理
			do
			{
				printf("process\n");
				//接收數據
				memset(buf,0,sizeof(buf));
				rval = recv(newSocket,buf,1024,0);

				
				if (rval == SOCKET_ERROR)
					//這應該是個異常,當客戶端沒有調用closeSocket就直接退出游戲的時候,將會進入這里
					printf("recv socket error\n");

				
				
				if (rval == 0)
					//recv返回0表示正常退出
					printf("ending connection");
				else
					//顯示接收到的數據
					printf("recv %s\n",buf);


			}while(rval != 0);

			//關閉對應Accept的socket
			closesocket(newSocket);
		}
		

		
	} while (1);

	//關閉自身的Socket
	closesocket(m_sock);
}


 

 

#include "ServerNet.h"

int main(int argc, char **argv)
{
	CServerNet serverNet;
	int iRlt = serverNet.Init("127.0.0.1",8888);
	if (iRlt == 0)
	{
		printf("init ok...\n");
		serverNet.Run();
	}
	else
		printf("serverNet init failed with error : %d\n",iRlt);
	system("pause");
}

 

 


#pragma once/*ClinetNet:用於表示一個客戶的網絡操作*/#include <stdio.h>#include<windows.h>#pragma comment(lib, "Ws2_32.lib")class CClientNet{public://連接上指定服務器int Connect(int port,const char* address);//發送信息int SendMsg(const char* msg,int len);//關閉void Close();private:SOCKET m_sock;};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM