對於socket的用途,大家都對此很熟悉了。socket的編程總體分爲服務端的編程和客戶端的編程。類型我們常用的有TCP、UDP兩種類型。
服務端的編程步驟:
1.初始化socket庫。
2.綁定本機地址和端口。(服務端特有)
3.監聽端口,等待客戶端連接。
4.當有客戶端連接,進行處理,但後繼續監聽或者結束程序。
5.退出程序,關閉socket,終止對socket庫的使用。
1、這裏我採用的MFC框架,首先在StdAfx.h頭文件添加socket頭文件和lib文件
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
2、初始化socket庫。這裏主要的工作就是定義了socket的版本,並將信息返回到wsadata結構體中
WSADATA wsd;
int ret=WSAStartup(MAKEWORD(2,2),&wsd);
if (ret!=0)
{
return FALSE;
}
if (HIBYTE(wsd.wVersion)!=2||LOBYTE(wsd.wVersion)!=2)
{
AfxMessageBox("初始化Socket失敗!");
WSACleanup();
return FALSE;
}
3、創建socket。在創建socket的時候,第一個參數定義了協議域,AF_IET表示採用IPV4(32位)與端口號(16位)的組合;第二個參數是socket類型,sock_stream流式指的是TCP、sock_dgram指的是UDP;第三個參數是協議類型常用協議IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,分別對應TCP傳輸協議、UDP傳輸協議、STCP傳輸協議、TIPC傳輸協議*/,我們可以填寫0這樣就可以自適應。
//創建
MySocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (MySocket==INVALID_SOCKET)
{
int iError=WSAGetLastError();
CString strMsg;
strMsg.Format("Failed socket(),Error Code is %d\n",iError);
AfxMessageBox(strMsg);
return ;
}
4、設置服務端信息。我們用到了sockaddr_in這個結構體,需要關注的三個參數,第一個是IP地址,也就是要服務器要綁定的IP地址,可以自己指定也可以設置成這樣。saddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //定義IP地址;第二個參數是協議類型,更上面創建的時候對應;第三個就是端口號了。
//設置服務器信息
sockaddr_in ServerAddr;
CString localIP; //獲取本地IP地址
char hostname[MAX_PATH] = {0};
gethostname(hostname,MAX_PATH);
hostent* ptent = gethostbyname(hostname);
if (ptent)
{
localIP = inet_ntoa(*(in_addr*)ptent->h_addr_list[0]);
}
ServerAddr.sin_addr.S_un.S_addr=inet_addr(localIP.GetBuffer(0));
ServerAddr.sin_family=AF_INET;
ServerAddr.sin_port=htons(4600);//1024 ~ 49151:普通用戶註冊的端口號
5、綁定。第一個參數是服務器端的socket,第二個參數存儲了服務器的一些信息上面定義好的。
//綁定
if (bind(MySocket,(SOCKADDR *)&ServerAddr,sizeof(SOCKADDR))==SOCKET_ERROR)
{
int iError=WSAGetLastError();
CString strMsg;
strMsg.Format("Failed Bind,Error Code is %d\n",iError);
AppendText(strMsg);
}
6、監聽客戶端的連接。第一個參數的服務器的socket,第二個參數是可以連接的客戶端最大個數。開始,我一直不太理解第二個參數,認爲是連接一個客戶端後的參數,經過我測試證明,確實是可以連接客戶端的最大個數。
//監聽客戶端連接
if(listen(MySocket,2)==SOCKET_ERROR)
{
int iError=WSAGetLastError();
CString strMsg;
strMsg.Format("Failed listen,Error Code is %d\n",iError);
AppendText(strMsg);
}
7、等待客戶端的連接。如果有多個客戶端同時連接,在此處可以開闢多個線程去處理。一個線程對應於一個客戶端,accept()函數,第一個參數爲Server端socket,第二個爲SOCKADDR結構體。如果執行成功,則會返回客戶端的socket和存有客戶端socket信息的結構體
//中斷等待連接
SOCKADDR_IN ClientAddr;
int len=sizeof(sockaddr);
pDlg->ClientSocket=accept(pDlg->MySocket,(SOCKADDR *)&ClientAddr,&len);
if (pDlg->ClientSocket==INVALID_SOCKET)
{
int iError=WSAGetLastError();
CString strMsg;
strMsg.Format("Failed accept,Error Code is %d\n",iError);
pDlg->AppendText(strMsg);
}
8、發送數據。send函數第一個參數客戶端socket,第二個參數發送的數據,返回發送成功的字符個數。這裏需要注意的是發送的時候,需要加1。把字符串最後的'\0'發送過去。
char SendBuf[1024];
sprintf(SendBuf,"%s",str);
if(send(ClientSocket,SendBuf,strlen(SendBuf)+1,0)==SOCKET_ERROR)
{
int iError=WSAGetLastError();
CString strMsg;
strMsg.Format("Failed send,Error Code is %d\n",iError);
AppendText(strMsg);
}
9、接收數據。recv函數,第一個參數爲客戶端socket,返回的是接收的字符個數。如果,接收失敗,則關閉客戶端socket
num=recv(pDlg->ClientSocket,RecBuf,1024,0);
if (num>=0)
{
RecBuf[num]='\0';
CString str;
str.Format("收到:%s\r\n",RecBuf);
pDlg->AppendText(str);
}
else
{
int iError=WSAGetLastError();
CString strMsg;
strMsg.Format("Failed recv,Error Code is %d\n",iError);
pDlg->AppendText(strMsg);
closesocket(pDlg->ClientSocket);
以上就是服務端的程序。