
我觉得MFC的东西挺难说的,好像代码没有一个头,也没有一个尾,不知道从何讲起。所以我只说说socket的部分,当然包括服务端和客户端。
这是服务端的样子:

那么这段代码是干嘛的呢,进去分析一下,是个线程创建函数,其中main是线程中的主调函数,svcname是线程参数,该线程参数最后被传做main函数的参数。看代码就会发现他需要 c语言函数,这是比较蛋疼的,更蛋疼的是你需要手动处理线程的各个状态的转换即管理生命周期,比如,这段代码虽然创建了一个线程,但并没有销毁。这对比多进程的fork()来说,从代码上看会更直观mfc socket 是否无效,只是我们必须要分清楚调用一个函数,和新建一个线程去调用一个函数,之间的差别:新建线程去调用函数,这个操作会很快的结束,并不会依序去执行那个函数,而是代表着,那个函数中的代码,可能和线程调用之后的代码,交替的执行。
DWORD WINAPI ListenThreadFunc(LPVOID Lparam)
Cxads_PCServerDlg * pServer = (Cxads_PCServerDlg *)Lparam;
if(INVALID_SOCKET == (pServer->m_SockListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)))
AfxMessageBox(_T("建立socket失败"));
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = htonl(INADDR_ANY);

service.sin_port = htons(pServer->m_ServicePort);
if(0 != bind(pServer->m_SockListen,(sockaddr *)&service,sizeof(sockaddr_in)))
AfxMessageBox(_T("绑定端口失败"));
if(0 != listen(pServer->m_SockListen,5))
//提示建立socket成功
pServer->EnableWindow(IDC_BUTTONEND,TRUE);
// pServer->EnableWindow(IDC_BUTTONSEND,TRUE);
pServer->EnableWindow(IDC_BUTTONSTART,FALSE);
pServer->SetRevBoxText(_T("服务启动成功,开始端口"));
//进入循环,端口

if n >:100 有效耗时。=if(and(right(a1*100,1)="0",right(a1*10,1)="5")=true,if(int(a1)/2=int(int(a1)/2),int(a1),round(a1,0)),round(a1,0))。done_log "minsize=${minsize}, mindisk=${mindisk}"_log "maxsize=${maxsize}, maxdisk=${maxdisk}"[ ${minsize} -gt 100 ] && {if [ "${mindisk}/meta" 。
sockaddr_in clientAddr;
intiLen = sizeof(sockaddr_in);
SOCKET accSock = accept(pServer->m_SockListen,(structsockaddr *)&clientAddr,&iLen);
if(accSock == INVALID_SOCKET)
continue;
//将节点加入链中
CClientItem tItem;
tItem.m_ClientSocket = accSock;
char *qqip=inet_ntoa(((sockaddr_in *)to)->sin_addr)。sprintf(sendbuf,"welcome %s to ",inet_ntoa(add_client.sin_addr))。 nsstring *ip = [nsstring stringwithformat:@"%s",inet_ntoa(addr- >sin_addr)]。
tItem.m_pMainWnd = pServer;

如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,则服务器将应远等待客户端的数据,保活功能就是试图在服务 器端检测到这种半开放的连接。如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据mfc socket 是否无效,则服务器将永远等待客户端的数据,保活功能就是试图在服务器端检测到这种半开放的连接。a:在同一个时间内,vnc服务器只接受一个(最后连接成功的那个)来自客户端的被动连接,但是,如果让要连接的客户机端先处于“”状态,再来由vnc服务器端进行主动连接,就可以实现多个客户机端同时连接上vnc服务器。
tItem.m_hThread = CreateThread(NULL,0,ClientThreadProc,//创建一个线程并挂起:CREATE_SUSPENDED
&(pServer->m_ClientArray.GetAt(idx)),CREATE_SUSPENDED,NULL);
pServer->m_ClientArray.GetAt(idx).m_hThread = tItem.m_hThread;
//等把hThread加入了节点,才开始执行线程,如下
ResumeThread(tItem.m_hThread);
pServer->SetRevBoxText(tItem.m_strIp + _T("上线"));
Sleep(100);
Cxads_PCServerDlg是我们对话框程序的类,我们传进来的参数就是这个类对象。pServer指向该对象。
if ((listenfd=socket(af_inet,sock_stream,0))==-1)。if ((fd = socket(af_inet, sock_stream, ipproto_tcp)) == -1)。if((fd=socket(af_inet,sock_stream,0))==-1)。
socket函数初始化一个socket。socket是什么?socket相当于通信的一个管道,m_SockListen是一个的socket。我们一会就要这根"管道",看是否有客户端连接。socket()中的参数像我这样写,代表这是个TCP连接。TCP连接和UDP连接的区别就是,TCP是要双方建立连接后才能通信,就想打电话;而UDP是单方面就能发送信息,就想发短信。

if (connect(fd, (struct sockaddr *)&raddr, sizeof(struct sockaddr_in)) == -1)。 if (connect(*fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) < 0) 。if(bind(sock,(sockaddr *)&addr_in,sizeof(sockaddr))==socket_error)。
bind函数是绑定一个端口和IP地址。第一个参数是刚才新建的socket,第二个参数是一个sockaddr_in结构体,里面保存着IP地址和端口。因为我们这是服务端,所以保存的IP地址和端口是自己的,htonl(INADDR_ANY)就是将IP地址绑定为任意,这样你的IP可以是127.0.0.1,也可以是192.168.x.x,也可以是你的外网IP。htons(pServer->m_ServicePort)是要的IP,我这里是从输入框获取的,你也可以使用固定的比如htons(8260)。
3.listen(pServer->m_SockListen,5)
开始了。5代表等待连接队伍的最大长度,一般都是5就行。
4.
进入while循环,大家可以看到这是个死循环。while(TRUE)永远不会退出去。while中间只有个if语句,socket_Select(pServer->m_SockListen,100,TRUE)是一个select选择模型,作用是向socket中看一眼,如果有信息则返回TRUE,如果没有信息则返回FALSE。有信息代表有客户端来连接了,于是我们进入if语句。
5.SOCKET accSock = accept(pServer->m_SockListen,(struct sockaddr*)&clientAddr,&iLen);
大家可以看到我又建了一个socket,不是刚才那个了。accept函数就返回一个socket,这个socket就是和该客户端通信的"管道"。传入的参数和bind类似,只是第二个变成得到客户端的IP与端口了。
6.
之后有一个将节点加入链表的过程。因为我们连接服务端的客户端不止一个,所以我们要将每一个客户端的IP、SOCKET和相关信息加入链表,以供以后使用。而且大家可以看到,我们这个while里面又新开了一个线程,这个线程的作用就是和该客户端通信。
7.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-118367-1.html
直接撞沉
奶粉是干的不