TCP/IP、UDP、Socket编程这几个词你熟悉吗?随着网络技术的发展,这些话充斥着我们的耳朵。那请问:1.什么是TCP/IP和UDP?2、Socket在哪里?3、什么是套接字?4.你会用吗?什么是TCP/IP、UDP?TCP/IP(传输控制协议/Internet协议)或传输控制协议/Internet协议是为广域网(WAN)设计的行业标准协议集。UDP(UserDataProtocol,用户数据报协议)是对应于TCP的协议。它是TCP/IP协议族之一。下图显示了这些协议的关系。图1TCP/IP协议族包括传输层、网络层和链路层。现在您知道了TCP/IP和UDP之间的关系。套接字在哪里?在图1中,我们没有看到Socket的影子,那么它在哪里呢?还是用图片说话,一目了然。图2.原来的Socket在这里。什么是套接字?Socket是应用层与TCP/IP协议族之间进行通信的中间软件抽象层,是一组接口。在设计模式上,Socket实际上是一种门面模式,将复杂的TCP/IP协议族隐藏在Socket接口的背后。对于用户来说,一套简单的接口就是全部,Socket组织数据以满足指定的协议。你用它们吗?前辈们为我们做了很多,网络之间的通信也简单了很多,但毕竟还有很多工作要做。以前听到Socket编程的时候,以为是比较高深的编程知识,但是只要搞清楚Socket编程的工作原理,神秘的面纱就会揭开。生活中的一幕。你想给朋友打电话,先拨号码,朋友听到铃声后拿起电话,你和朋友就建立了联系,可以通话了。交流结束后,挂断电话结束通话。生活中的场景说明了这一工作原理。或许生活中就诞生了TCP/IP协议族,其实不一定。图3从服务器端开始。服务端先初始化Socket,然后绑定端口,监听端口,调用accept阻塞,等待客户端连接。这时如果客户端初始化一个Socket,然后连接到服务器(connect),如果连接成功,那么客户端和服务器的连接就建立了。客户端发送数据请求,服务端接收并处理请求,然后将响应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。这里我举一个简单的例子,我们走的是TCP协议的路径(见图2)。例子是用MFC写的,运行界面如下:图4图5在客户端输入服务器的IP地址和要发送的数据,然后按下发送按钮,服务器接收数据,并然后响应客户端。客户端读取响应数据并显示在界面上。#p#下面是接收和发送数据的函数:intReceive(SOCKETfd,char*szText,intlen){intcnt;内部;cnt=长度;while(cnt>0){rc=recv(fd,szText,cnt,0);如果(rc==SOCKET_ERROR){return-1;}if(rc==0)returnlen-cnt;szText+=rc;cnt-=rc;}返回长度;}intSend(SOCKETfd,char*szText,intlen){intcnt;内部;cnt=长度;while(cnt>0){rc=send(fd,szText,cnt,0);如果(rc==SOCKET_ERROR){return-1;}if(rc==0)returnlen-cnt;szText+=rc;cnt-=rc;}返回长度;}服务器端:在服务器端,主要是启动Socket和监听线程。#defineDEFAULT_PORT2000voidCServerDlg::OnStart(){sockaddr_inlocal;DWORDdwThreadID=0;local.sin_family=AF_INET;//设置的端口为DEFAULT_PORT。local.sin_port=htons(DEFAULT_PORT);//IP地址设置为INADDR_ANY,这样系统就可以自动获取本机的IP地址。local.sin_addr.S_un.S_addr=INADDR_ANY;//初始化套接字m_Listening=socket(AF_INET,SOCK_STREAM,0);如果(m_Listening==INVALID_SOCKET){返回;}//给创建的socket绑定本地地址If(bind(m_Listening,(LPSOCKADDR)&local,sizeof(local))==SOCKET_ERROR){closesocket(m_Listening);返回;}//创建一个监听线程,这样它也可以响应界面上的操作。m_hListenThread=::CreateThread(NULL,0,ListenThread,this,0,&dwThreadID);m_StartBtn.EnableWindow(FALSE);m_StopBtn.EnableWindow(TRUE);}监听线程函数:DWORDWINAPICServerDlg::ListenThread(LPVOIDlpparam){CServerDlg*pDlg=(CServerDlg*)lpparam;如果(pDlg==NULL)返回0;SOCKETListening=pDlg->m_Listening;//开始监听客户端连接。if(listen(Listening,40)==SOCKET_ERROR){return0;}charszBuf[MAX_PATH];//初始化内存集(szBuf,0,MAX_PATH);while(1){SOCKETConnectSocket;sockaddr_inClientAddr;intnLen=sizeof(sockaddr);//阻塞直到有客户端连接,否则会浪费CPU资源。ConnectSocket=accept(Listening,(sockaddr*)&ClientAddr,&nLen);//全部到客户端的IP地址。char*pAddrname=inet_ntoa(ClientAddr.sin_addr);pDlg->Receive(ConnectSocket,szBuf,100);//请求数据显示在界面上。pDlg->SetRequestText(szBuf);strcat(szBuf,":我是老猫,收到了(");strcat(szBuf,pAddrname);strcat(szBuf,")");//向客户端发送响应数据pDlg->Send(ConnectSocket,szBuf,100);}返回0;}服务端一直监听是否有客户端连接,如果有连接,处理客户端的请求,给出响应,然后继续监听。客户端:客户端发送函数:#defineDEFAULT_PORT2000voidCClientDlg::OnSend(){DWORDdwIP=0;TCHARszText[MAX_PATH];memset(szText,0,MAX_PATH);m_IP.GetWindowText(szText,MAX_PATH);//把字符串形式的IP地址转换成IN_ADDR结构体要求的形式。dwIP=inet_addr(szText);m_RequestEdit.GetWindowText(szText,MAX_PATH);sockaddr_inlocal;SOCKETsocketTmp;//必须是AF_INET,表示socket在Internet域内通信local.sin_family=AF_INET;//端口号local.sin_port=htons(DEFAULT_PORT);//服务器IP地址。local.sin_addr.S_un.S_addr=dwIP;////初始化套接字socketTmp=socket(AF_INET,SOCK_STREAM,0);//连接到服务器if(connect(socketTmp,(LPSOCKADDR)&local,sizeof(local))<0){closesocket(socketTmp);MessageBox("连接服务器失败。");返回;}//发送请求,为了简单只发送100字节,服务器端也指定了100字节。发送(socketTmp,szText,100);//读取服务器返回的数据。memset(szText,0,MAX_PATH);//接收服务器的响应。接收(socketTmp,szText,100);TCHARszMessage[MAX_PATH];memset(szMessage,0,MAX_PATH);strcat(szMessage,szText);//在界面上显示响应数据。m_ReplyBtn.SetWindowText(szMessage);关闭套接字(socketTmp);}客户端完成一个函数的通信。为什么在这里使用127.0.0.1作为IP地址?使用这个IP地址,服务端和客户端可以在同一台机器上运行,调试起来就方便多了。当然,你可以在朋友的机器上运行Server程序(我在局域网测试过),在自己的机器上运行Client程序。当然,输入的IP地址应该是你朋友机器的IP地址。简单的理论和实践都说了,现在Socket编程也不神秘了吧?希望对你有所帮助。原文链接:http://www.cnblogs.com/goodcandle/archive/2005/12/10/socket.html
