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;};
