socket編程筆記

對於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);

以上就是服務端的程序。










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章