在学习网络编程之前,我们需要对Tcp/ip协议栈有个清楚地了解。Tcp/ip协议栈分以下五层,也有分成7层
5、应用层
4、传输层
3、网络层
2、数据链路层
1、物理层
物理层是实实在在的物理链路,它为上层协议提供了一个传输数据的物理媒体,负责将数据以比特流的方式收发、接收。数据链路层主要负责物理传输的准备,MAC地址和交换机都工作在这一层。网络层主要负责管理网络地址、定位设备、决定路由。路由器就工作在这一层。作用是将网路地址翻译成物理地址,并决定将数据从发送方路由到接收方。应用层,一般是指应用程序,该层主要负责确定通信对象,并确保有足够资源用于通信。根据传输层的端口信息调用不同的程序来处理传输的内容,端口8080是http报文,端口21是ftp报文。
物理层关心的是如何把电气信号变成一段报文;数据链路层关心的是mac地址、vlan、优先级等;网络层关心的是ip地址,下一跳ip;传输层关心的是端口资源;应用层关心的是报文组装、解析、渲染、存储、执行等等。
在学习网络编程之前,学习socket的工作原理是很有必要的。我们需要为它配置端口信息和ip地址。配置完了之后,我们就可以慢慢等待报文的收发了。所以一般来说,作为服务器端口的处理流程是这样的:
a) 创建socket b) 绑定socket到特定的ip地址 c) 对socket进行侦听处理 d) 接受socket,表明有客户端和服务器连接 e) 和客户端循环收发报文 f) 关闭socket
客户端的处理流程就相对简单一点了,只需要 a) 创建socket b) 链接服务器端地址 c) 和服务器端的socket收发报文
一、Winsocket用TCP协议来完成通信
①服务器的程序
// SocketSever.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <Winsock2.h> #include <stdio.h> #include <stdlib.h> #pragma comment(lib,"WS2_32.LIB") #if DUBUG #define AF_INET 2 /* internetwork: UDP, TCP, etc. */ #define SOCK_STREAM 1 /* stream socket */ #define SOCK_DGRAM 2 /* datagram socket */ #define SOCK_RAW 3 /* raw-protocol interface */ #define SOCK_RDM 4 /* reliably-delivered message */ #define SOCK_SEQPACKET 5 /* sequenced packet stream */ /* * Socket address, internet style. */ struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; typedef struct sockaddr_in SOCKADDR_IN; /* Microsoft Windows Extended data types */ int bind( SOCKET s, const struct sockaddr FAR * name, int namelen ); /* INCL_WINSOCK_API_PROTOTYPES*/ int listen( SOCKET s, int backlog ); #endif #define Port 3578 #define MaxSize 1024 SOCKADDR_IN addrSrv; SOCKADDR_IN addrClient; SOCKET sockSrv; //服务器 SOCKET sockConn; //********************************************************************************************************/ //** 函数名 ** StartSock() //** 输入 ** 无 //** 输出 ** 无 //**函数描述** 加载套接字 //********************************************************************************************************/ int SocketInit() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested=MAKEWORD(2,2); err = WSAStartup(wVersionRequested,&wsaData); //返回0,成功,否则就是错误码 if (err!=0) { printf("WinSock DLL版本不足要求n"); return 0; } if (LOBYTE(wsaData.wVersion)!=2|| HIBYTE(wsaData.wVersion)!=2) { WSACleanup(); return 0; } return 1; } //********************************************************************************************************/ //** 函数名 ** main() //** 输入 ** 无 //** 输出 ** 无 //**函数描述** 主函数 //********************************************************************************************************/ int main() { if (SOCKET_ERROR ==SocketInit()) { return -1; } SOCKADDR_IN addrSrv;//存放本地地址信息的 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//htol将主机字节序long型转换为网络字节序 addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6001);//htos用来将端口转换成字符,1024以上的数字即可 //真正socket编程部分 SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);//面向连接的可靠性服务SOCK_STRAM bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//将socket绑定到相应地址和端口上 listen(sockSrv,5);//等待队列中的最大长度为5 printf("%s\n","Welcome,the Host is running!Now Wating for someone comes in!"); SOCKADDR_IN addrClient; int iSend = 0; char sendBuf[MaxSize]; char revBuf[MaxSize]; int len=sizeof(SOCKADDR); while(1) //循环监听客户端,永远不停止 { sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);//阻塞调用进程直至新的连接出现 if(sockConn == INVALID_SOCKET) { printf("Accept Failed!\n"); return -1; } sprintf(sendBuf,"Server IP is:%s",inet_ntoa(addrClient.sin_addr));//inet_nota函数是将字符转换成ip地址 iSend = send(sockConn,sendBuf,strlen(sendBuf)+1,0);//服务器向客户端发送数据 if(iSend == SOCKET_ERROR) { printf("send Failed!"); break; } char recvBuf[100]; recv(sockConn,recvBuf,100,0);//服务器从客户端接受数据 printf("%s\n",recvBuf); closesocket(sockConn);//关闭socket } closesocket(sockConn); //关闭套接字 getchar(); return 0; }②客户端的程序
<pre name="code" class="cpp">#include "stdafx.h" #include <Winsock2.h> #include <stdio.h> #include <string.h> #pragma comment(lib,"WS2_32.LIB") //********************************************************************************************************/ //** 函数名 ** StartSock() //** 输入 ** 无 //** 输出 ** 无 //**函数描述** 加载套接字 //********************************************************************************************************/ int SocketInit() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested=MAKEWORD(2,2); err = WSAStartup(wVersionRequested,&wsaData); //返回0,成功,否则就是错误码 if (err!=0) { printf("WinSock DLL版本不足要求n"); return 0; } if (LOBYTE(wsaData.wVersion)!=2|| HIBYTE(wsaData.wVersion)!=2) { WSACleanup(); return 0; } return 1; } //********************************************************************************************************/ //** 函数名 ** main() //** 输入 ** 无 //** 输出 ** 无 //**函数描述** 主函数 //********************************************************************************************************/ int main() { //固定格式 char recvBuf[1024]; if (SOCKET_ERROR ==SocketInit()) { return -1; } //建立通讯socket SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=inet_addr("192.168.1.100");//设定需要连接的服务器的ip地址 addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6001);//设定需要连接的服务器的端口地址 connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//与服务器进行连接 //接受来自老师的信息 int iRevLen = 0; iRevLen = recv(sockClient,recvBuf,strlen(recvBuf)+1,0); if(0 == iRevLen) { return -1; } else if(SOCKET_ERROR == iRevLen) { printf("Recv Failed\n!"); return -1; } printf("%s\n",recvBuf); char str[100]; gets(str); send(sockClient,str,strlen(str)+1,0); closesocket(sockClient); WSACleanup(); getchar(); return -1; }