Windows Socket網(wǎng)絡(luò)編程_第1頁
Windows Socket網(wǎng)絡(luò)編程_第2頁
Windows Socket網(wǎng)絡(luò)編程_第3頁
Windows Socket網(wǎng)絡(luò)編程_第4頁
Windows Socket網(wǎng)絡(luò)編程_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、 Windows Socket 網(wǎng)絡(luò)通信程序設(shè)計(jì)一、理論分析同步方式指的是發(fā)送方不等接收方響應(yīng),便接著發(fā)下個(gè)數(shù)據(jù)包的通信方式;而異步指發(fā)送方發(fā)出數(shù)據(jù)后,等收到接收方發(fā)回的響應(yīng),才發(fā)下一個(gè)數(shù)據(jù)包的通信方式。       阻塞套接字是指執(zhí)行此套接字的網(wǎng)絡(luò)調(diào)用時(shí),直到成功才返回,否則一直阻塞在此網(wǎng)絡(luò)調(diào)用上,比如調(diào)用recv()函數(shù)讀取網(wǎng)絡(luò)緩沖區(qū)中的數(shù)據(jù),如果沒有數(shù)據(jù)到達(dá),將一直掛在recv()這個(gè)函數(shù)調(diào)用上,直到讀到一些數(shù)據(jù),此函數(shù)調(diào)用才返回;而非阻塞套接字是指執(zhí)行此套接字的網(wǎng)絡(luò)調(diào)用時(shí),不管是否執(zhí)行成功,都立即返回。比如調(diào)用recv()函數(shù)

2、讀取網(wǎng)絡(luò)緩沖區(qū)中數(shù)據(jù),不管是否讀到數(shù)據(jù)都立即返回,而不會(huì)一直掛在此函數(shù)調(diào)用上。在實(shí)際Windows 網(wǎng)絡(luò)通信軟件開發(fā)中,異步非阻塞套接字是用的最多的。平常所說的C/S(客戶端/服務(wù)器)結(jié)構(gòu)的軟件就是異步非阻塞模式的。 使用的是傳統(tǒng)的socket  (recv(),send() .)等。而且是阻塞模式,使用圖形界面MFC編寫 (VC 6.0)但為了能讓程序不出現(xiàn)假死現(xiàn)象( recv,accept  這樣的函數(shù)都會(huì)出現(xiàn)這樣的事情),所以采用了多線程技術(shù),其實(shí)也就是用了AfxBeginThread ,TerminateThread等等。這樣對(duì)于阻塞函數(shù)都讓他們?cè)谛陆⒌木€程里運(yùn)行

3、就好了。另外解決的一個(gè)大問題就是,創(chuàng)建的新線程無法對(duì)窗口進(jìn)行操作,比如要自在編輯框顯示一句話等等。如果直接取得窗口類的句柄操作,會(huì)出現(xiàn)wincore 的錯(cuò)誤,也就是跨線程錯(cuò)誤。主要原因也就是-MFC的線程被自己外部創(chuàng)建的線程調(diào)用就會(huì)有這個(gè)錯(cuò)誤。解決的方法就是在線程里用SendMessage給窗口發(fā)送一個(gè)自定義的消息。比如我這里用的就是 要實(shí)現(xiàn)這樣的方法在BEGIN_MESSAGE_MAP下面要添加ON_MESSAGE(WM_UpdateDATA, OnMyMessage)   綁定我自己的消息,這樣外部的線程就可以通過SendMessage來調(diào)用窗體的函數(shù)OnMy

4、Message了,用來顯示信息WM_UpdateDATA在stdafx.h中我自己定義為#define WM_UpdateDATA WM_USER+100 。定義一個(gè)自己的消息*/這樣只要外部給窗口SendMessage  ->  WM_UpdateDATA 就會(huì)讓窗口的onmymessage函數(shù)執(zhí)行了,具體要顯示的內(nèi)容放在一個(gè)全局變量就好了。 serverdlg.cpp 二、程序代碼/定義全局變量,方便各個(gè)工作線程和窗口線程的通信SOCKETsockuse,sock;int flag; /主要是用來標(biāo)志是否連接,用來控制一些循環(huán)和功能HWND m

5、ydlg; /記錄窗體的句柄HWND stopbutton; /記錄關(guān)閉連接按鈕的句柄 char buff200; /主要的緩沖區(qū),顯示數(shù)據(jù)使用,也供線程間通信使用 CWinThread* mainthread; /記錄線程的句柄 UINT FileTrans(LPVOID pParam) /發(fā)送文件的線程函數(shù)  OPENFILENAMEA ofn; char szFile260; char path260; char filebuff100; int num; ZeroMemory(&ofn, sizeof(ofn); ofn.lStructS

6、ize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFile = szFile; ofn.lpstrFile0 = '0' ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = "所有文件*.*0" ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = 0; /以上的定義是為了建立一個(gè)文件打開對(duì)話框。

7、步驟/上來說都是固定的,這里只是借用一下 if (GetOpenFileNameA(&ofn)=FALSE) /判斷文件路徑取得是否正確 /若失敗則恢復(fù)建立MainControl線程,進(jìn)行數(shù)據(jù)接收處理。 mainthread=AfxBeginThread(MainControl,NULL); flag=1; /設(shè)定flag保證MainControl可以正常進(jìn)行循環(huán)return 0; memset(filebuff,0,100); /清空filebuff strcpy(path,ofn.lpstrFile); /將路徑拷貝到path中 strcpy(filebuff,"send

8、start"); send(sockuse,filebuff,strlen(filebuff),0); /發(fā)送請(qǐng)求信息 recv(sockuse,filebuff,100,0); /等待接收反饋信息 if(strcmp(filebuff,"sendagree") /若接收到的信息不是sendagree strcpy(buff,"對(duì)方接受錯(cuò)誤"); SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息 mainthread=AfxBeginThread(MainControl,NULL

9、); /恢復(fù)建立MainControl線程 flag=1; /設(shè)定flag保證MainControl循環(huán)正常 return 0;SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息  while(!feof(fp)   num=fread(filebuff,1,100,fp); /文件結(jié)束前每次讀取100字節(jié) send(sockuse,filebuff,num,0); /發(fā)送,最后一次不足100字節(jié) /作為標(biāo)志,可以讓接受方知道文件結(jié)束 strcpy(buff,"發(fā)送完畢");SendMess

10、age(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息memset(buff,0,100);fclose(fp); /關(guān)閉文件  flag=1; return 0;  UINT FileRecv() /接收文件函數(shù) char sendbuff100; /發(fā)送緩沖區(qū)char recvbuff100; /接受緩沖區(qū)int num; /記錄每次接受的字節(jié)數(shù)  CString szGetName; /記錄保存的文件路徑CFileDialog * lpszOpenFile; /定義一個(gè)CfileDialog對(duì)象

11、lpszOpenFile=new CFileDialog(false,"","",OFN_FILEMUSTEXIST|OFN_HIDEREADONLY,"文件類型(*.*)|*.*|");/生成一個(gè)對(duì)話框if(lpszOpenFile->DoModal()=IDOK)/假如點(diǎn)擊對(duì)話框確定按鈕szGetName = lpszOpenFile->GetPathName(); /得到打開文件的路徑/SetWindowText(szGetName); /在窗口標(biāo)題上顯示路徑delete lpszOpenFile; /釋放分配的對(duì)話

12、框memset(sendbuff,0,100);  strcpy(sendbuff,"sendagree"); send(sockuse,sendbuff,strlen(sendbuff),0); /發(fā)送sendagree告知對(duì)方開始發(fā)送吧  SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯/示信息 num=recv(sockuse,recvbuff,100,0); /接收數(shù)據(jù)FILE *fp=fopen(szGetName,"wb"); /打開文件,路徑為szGe

13、tNamefwrite(recvbuff,num,1,fp); /寫入之前的數(shù)據(jù)  num=recv(sockuse,recvbuff,100,0); fwrite(recvbuff,num,1,fp);  fclose(fp); /結(jié)束后關(guān)閉文件。 strcpy(buff,"接收完畢");SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,/顯示信息return 0; int Addrlen=sizeof(sockaddr_in); /accept要用到的數(shù)值sockaddr_i

14、n ClientAddr; sockuse=accept(sock,(struct sockaddr FAR *)&ClientAddr,&Addrlen);/上一句的accept函數(shù)調(diào)用后會(huì)進(jìn)行阻塞,造成未返回時(shí)程序假死,使用了單獨(dú)的線程/就是為了防止這樣的現(xiàn)象發(fā)生flag=1; /返回成功后,設(shè)定flag保證MainControl循環(huán)正常strcpy(buff,"已經(jīng)連接!");SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消/息,顯示信息mainthread=AfxBeginThread(MainC

15、ontrol,NULL); /建立MainControl線程      return 0;   char recvbuff100; /接受緩沖區(qū)memset(buff,0,100);while(flag)memset(recvbuff,0,100); /每次接收前清空緩沖區(qū) recv(sockuse,recvbuff,100,0); /進(jìn)行阻塞接收數(shù)據(jù),如果不是用單獨(dú)的線程/會(huì)造成程序假死,這也就是為什么我的程序使用單獨(dú)的線程來處理 if(!strcmp(recvbuff,"end")SendMessag

16、e(stopbutton,BM_CLICK,NULL,NULL); /消息判斷為end則調(diào)用/窗口的OnButtonEnd函數(shù)來結(jié)束連接的清理工作。return 0;else if(!strcmp(recvbuff,"sendstart")/接受的消息判斷為"sendstart"則調(diào)用FileRecv() FileRecv(); else strcpy(buff,"client:");strcat(buff,recvbuff);SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給/窗口消息,

17、顯示信息return 0;    m_ctrlstop.EnableWindow(true);  m_ctrlfile.EnableWindow(true);m_ctrlstart.EnableWindow(false);m_ctrlsend.EnableWindow(true); /以上使各個(gè)按鈕進(jìn)行使能 sockaddr_in ServerAddr; /開始建立socket WSADATA WSAData; if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0)showmess("SOCKET 初始化錯(cuò)誤

18、rn");return; sock=socket(AF_INET,SOCK_STREAM,0); /采用流式套接字,ipv4if(sock=SOCKET_ERROR)showmess("SOCKET 創(chuàng)建錯(cuò)誤!rn");WSACleanup(); return; ServerAddr.sin_family=AF_INET; ServerAddr.sin_addr.s_addr=htonl(INADDR_ANY); /任意ip作為本機(jī)ip ServerAddr.sin_port=htons(2006); /使用2006端口  if(bind(sock,(s

19、truct sockaddr FAR*)&ServerAddr,sizeof(ServerAddr)=SOCKET_ERROR) /綁定socket和本地地址showmess("綁定錯(cuò)誤!n");return;   /顯示正在偵聽 showmess("listening.");listen(sock,1);flag=0; /未連接之前,flag=0mydlg=this->GetSafeHwnd(); /取得窗口句柄供線程函數(shù)使用stopbutton=:GetDlgItem(mydlg,IDC_BUTT

20、ON_STOP); /取得關(guān)閉連接按/鈕的句柄供線程函數(shù)使用 AfxBeginThread(WaitForAccept,NULL); /啟動(dòng)WaitForAccept線程等待連接      return;   void CServerDlg:showmess(char *mess) /用來在信息窗口顯示信息   m_strmess+=mess; m_strmess+="rn" /在每條信息后添加回車UpdateData(false); /更新信息顯示   flag=0; /將

21、連接標(biāo)志清零strcpy(buff,"end"); send(sockuse,buff,strlen(buff),0); /給對(duì)方發(fā)送信息告知結(jié)束TerminateThread(mainthread->m_hThread,0x01); /結(jié)束MainControl線程closesocket(sock); /關(guān)閉套接字closesocket(sockuse);WSACleanup(); /清理網(wǎng)絡(luò) m_ctrlstop.EnableWindow(false); /使能一些按鈕m_ctrlfile.EnableWindow(false);m_ctrlstart.Enabl

22、eWindow(true);  void CServerDlg:OnMyMessage() showmess(buff); /僅僅是為了線程函數(shù)調(diào)用內(nèi)部的信息顯示函數(shù)  void CServerDlg:OnButtonFile()   flag=0; /設(shè)定 flag TerminateThread(mainthread->m_hThread,0x01); /中止MainControlAfxBeginThread(FileTrans,NULL); /啟用FileTrans線程  void CServerDlg:OnButtonS

23、end()  char talkbuff100;memset(talkbuff,0,100);UpdateData(true);strcpy(talkbuff,m_strtalk); /取得對(duì)話框數(shù)據(jù)send(sockuse,talkbuff,100,0); /發(fā)送給對(duì)方信息   clientDlg.cpp 首先是clientDlg.cpp #include "winsock.h" #include "stdio.h"#include"string.h"#pragm

24、a comment(lib,"wsock32.lib") /這四句要加在本文件的開頭部分。保證/網(wǎng)絡(luò)功能正常在BEGIN_MESSAGE_MAP下面要添加ON_MESSAGE(WM_UpdateDATA, OnMyMessage)   /*綁定我自己的消息,這樣外部的線程就可以通過SendMessage來調(diào)用窗體的函數(shù)OnMyMessage了,用來顯示信息 WM_UpdateDATA在stdafx.h中我自己定義為#define WM_UpdateDATA WM_USER+100 /定義一個(gè)自己的消息*/  /定義全局變量,方便各個(gè)工

25、作線程和窗口線程的通信SOCKET sock;char buff100; /主要的緩沖區(qū),顯示數(shù)據(jù)使用,也供線程間通信使用HWND mydlg; /記錄窗體的句柄sockaddr_in ServerAddr;int flag=0; /主要是用來標(biāo)志是否連接,用來控制一些循環(huán)和功能CWinThread* mainthread;HWND stopbutton; /記錄關(guān)閉連接按鈕的句柄   UINT WaitForConnect(LPVOID pParam) /等待connect 的線程 if(connect(sock,(struct sockaddr*)&

26、amp;ServerAddr,sizeof(ServerAddr)=SOCKET_ERROR)strcpy(buff,"connect failn");SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消/息,顯示信息closesocket(sock); /失敗則關(guān)閉sockreturn 0;strcpy(buff,"已經(jīng)連接!");SendMessage(mydlg,WM_UpdateDATA,NULL,NULL);/發(fā)送給窗口消/息,顯示信息flag=1;mainthread=AfxBeginThre

27、ad(MainControl,NULL); /建立MainControl線程return 0;  char sendbuff100; /發(fā)送緩沖區(qū)char recvbuff100; /接受緩沖區(qū)int num; /記錄每次接受的字節(jié)數(shù) CString szGetName;CFileDialog * lpszOpenFile; /定義一個(gè)CfileDialog對(duì)象lpszOpenFile = new CFileDialog(false,"","",OFN_FILEMUSTEXIST|OFN_HIDEREADONLY,"文件類型

28、(*.*)|*.*|");/生成一個(gè)對(duì)話框if(lpszOpenFile->DoModal()=IDOK)/假如點(diǎn)擊對(duì)話框確定按鈕szGetName = lpszOpenFile->GetPathName(); /得到打開文件的路徑/SetWindowText(szGetName); /在窗口標(biāo)題上顯示路徑delete lpszOpenFile; /釋放分配的對(duì)話框 memset(sendbuff,0,100); strcpy(sendbuff,"sendagree"); send(sock,sendbuff,strlen(sendbuff)

29、,0); /發(fā)送sendagree告知對(duì)方開始發(fā)送吧 SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息 num=recv(sock,recvbuff,100,0); /接收數(shù)據(jù)FILE *fp=fopen(szGetName,"wb"); /打開文件,路徑為szGetNamefwrite(recvbuff,num,1,fp); /寫入之前的數(shù)據(jù)   while(num=100) /根據(jù)接收是否為100字節(jié)判斷文件是否結(jié)束 num=recv(sock,recvbuff,100,0)

30、; fwrite(recvbuff,num,1,fp);  strcpy(buff,"接收完畢");SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息return 0; char recvbuff100;/接受緩沖區(qū)   memset(buff,0,100);  while(flag) memset(recvbuff,0,100); /每次接收前清空緩沖區(qū) recv(sock,recvbuff,100,0); /進(jìn)行阻塞接收數(shù)據(jù),如果不是用單獨(dú)的線程/

31、會(huì)造成程序假死,這也就是為什么我的程序使用單獨(dú)的線程來處理 if(!strcmp(recvbuff,"end") /消息判斷為end則調(diào)用/窗口的OnButtonEnd函數(shù)來結(jié)束連接的清理工作。SendMessage(stopbutton,BM_CLICK,NULL,NULL); return 0;else if(!strcmp(recvbuff,"sendstart")/接受的消息判斷為"sendstart"則調(diào)用FileRecv() FileRecv();memset(recvbuff,0,100); else strcpy(bu

32、ff,"server:");strcat(buff,recvbuff);SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息return 0;  OPENFILENAMEA ofn; char szFile260; char path260; char filebuff100; int num; ZeroMemory(&ofn, sizeof(ofn); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFile = sz

33、File; ofn.lpstrFile0 = '0' ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = "所有文件*.*0" ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = 0; /以上的定義是為了建立一個(gè)文件打開對(duì)話框。步驟/上來說都是固定的,這里只是借用一下   if (GetOpenFileNameA(&ofn)=

34、FALSE) /判斷文件路徑取得是否正確  /若失敗則恢復(fù)建立MainControl線程,進(jìn)行數(shù)據(jù)接收處理。 mainthread=AfxBeginThread(MainControl,NULL); flag=1; /設(shè)定flag保證MainControl可以正常進(jìn)行循環(huán)return 0; memset(filebuff,0,100); /清空filebuff strcpy(path,ofn.lpstrFile); /將路徑拷貝到path中 strcpy(filebuff,"sendstart"); send(sock,filebuff,strlen(filebu

35、ff),0); /發(fā)送請(qǐng)求信息 recv(sock,filebuff,100,0); /等待接收反饋信息 if(strcmp(filebuff,"sendagree") /若接收到的信息不是sendagree strcpy(buff,"對(duì)方接受錯(cuò)誤"); SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息 mainthread=AfxBeginThread(MainControl,NULL); /恢復(fù)建立MainControl線程 flag=1; /設(shè)定flag保證MainControl循環(huán)

36、正常 return 0;   strcpy(buff,"對(duì)方已經(jīng)同意,開始發(fā)送文件"); SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息  FILE *fp=fopen(path,"rb"); /打開文件  while(!feof(fp)  num=fread(filebuff,1,100,fp); /文件結(jié)束前每次讀取100字節(jié) send(sock,filebuff,num,0); /發(fā)送,最后一次不足100字節(jié) /

37、作為標(biāo)志,可以讓接受方知道文件結(jié)束 strcpy(buff,"發(fā)送完畢");SendMessage(mydlg,WM_UpdateDATA,NULL,NULL); /發(fā)送給窗口消息,顯示信息memset(buff,0,100);fclose(fp); /關(guān)閉文件 mainthread=AfxBeginThread(MainControl,NULL); /恢復(fù)建立MainControl線程 flag=1; return 0;  m_ctrlstop.EnableWindow(true);m_ctrlfile.EnableWindow(true);m_ctrlconn

38、ect.EnableWindow(false);/以上使各個(gè)按鈕進(jìn)行使能  WSADATA WSAData;/開始建立socket if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0)showmess("socket初始化錯(cuò)誤");return;   sock=socket(AF_INET,SOCK_STREAM,0);/采用流式套接字,ipv4 if(sock=SOCKET_ERROR)showmess("SOCK Create FAIL!");WSACleanup

39、(); return;ServerAddr.sin_family = AF_INET;ServerAddr.sin_port = htons(2006);/使用2006端口UpdateData(true); /讀取ip 值ServerAddr.sin_addr.s_addr = inet_addr(m_strip);/使用編輯框中的ip地址,默認(rèn)值   /取得窗口句柄供線程函數(shù)使用flag=0;stopbutton=:GetDlgItem(mydlg,IDC_BUTTON_STOP);/取得關(guān)閉連接按鈕的句柄供線程函數(shù)使用AfxBeginThread(WaitForConn

40、ect,NULL);/啟動(dòng)WaitForConnect線程進(jìn)行連接return;  m_strmess+=mess;m_strmess+="rn" /在每條信息后添加回車UpdateData(false); /更新信息顯示  void CClientDlg:OnMyMessage()  showmess(buff);/僅僅是為了線程函數(shù)調(diào)用內(nèi)部的信息顯示函數(shù)     TerminateThread(mainthread,0x01);/結(jié)束MainControl線程strcpy(buff,"end");send(sock,buff,strlen(buff),0);/給對(duì)方發(fā)送信息告知結(jié)束closesocket(sock);/關(guān)閉套接字 WSACleanup();m_ctrlstop.EnableWindow(false);/使一些按鈕m_ctrlfile.EnableWindow(false);m_ctrlconnect.EnableWindow(true);

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論