在Windows平台上主要有两个版本的Socket Api函数:
WinSock 1.1和WinSock 2.2 , 2.2版本默认兼容1.1版本,
1.1 winsock.h wsock32.lib winsock.dll
2.2 winsock2.h ws2 32.lib ws2 32.dll
2.0版本的Socket比1.1的多一些高级的功能如:
多重协议支持:通过SPI接口支持其他协议;
多重命名空间:根据服务与主机名选择协议
重叠10模式:增强10吞吐量与提高性能
分散与聚合:从多个缓冲区发送与接收数据
有条件接受:有选择性地决定是否接受连接;
套接字共享:多个进程共享一个套接字句柄。
Socket套接字类型:
比较常用的包括:流式套接字(使用TCP) ,数据报套接字(使用UDP) ,原始套接字等
TCP与UDP各有优缺点:
TCP :面向连接、稳定、需要资源多;
UDP :面向无连接(一般情况下)、不稳定、需要资源少。
用手机打电话时面向连接的,用手机发短信是面向无连接的,目前来说网络上比较常用的是TCP类型的衰接字。
TCP与UDP的区别:
1.基于连接与无连接
2.对系统资源的要求(TCP较多,UDP少)
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP)
TCP保证数据正确性, UDP可能丢包
TCP保证数据顺序, UDP不保证
具体编程时的区别
1. socket0的参数不同
2. UDP Server不需要淘用listen和accept
3. UDP收发数据用sendto/recvfrom函数
4. TCP:地址信息在connect/accept时确定
UDP :在sendto/recvfrom函数中每次均需指定地址信息
5. UDP : shutdown函数无效
部分满足以下几点要求时,应该采用UDP面向数据报方式
1.网络数据大多为短消息
2.拥有大量Client
3.对数据安全性无特殊要求
4.网络负担非常重,但对响应速度要求高
TCP类型Socket程序开发流程:
TCP服务端: WSASartup, socket, bind, listen, accept, read, write, closesocket, WSACleanup.
TCP客户端: WSASartup, socket, connect, read, write, closesocket, WSACleanup.
流程图:
这种结构虽然能不停地接收客户端新的连接,但不能处理复杂的业务。
服务器端:
#include<WinSock2.h> #include<Windows.h> #include<stdio.h> #include<iostream> #pragma comment(lib,"ws2_32.lib") int main() { WORD ver = MAKEWORD(2, 2); WSADATA dat; //WinSocket启动 WSAStartup(ver, &dat); //建立一个socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //AF_INET创建一个IPV4的套接字,SOCK_STREAM面向数据流的,IPPROTO_TCP TCP if (INVALID_SOCKET == _sock) { printf("ERROR:建立失败! "); } //1.绑定 sockaddr_in _sin = {}; //创建网络地址 _sin.sin_family = AF_INET; _sin.sin_port = htons(4567); //Host to Network Short _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // IP地址 if (bind(_sock, (sockaddr *)&_sin, sizeof(_sin)) == SOCKET_ERROR) { printf("ERROR:绑定失败! "); } else { printf("TRUE:绑定成功! "); } //2.监听网络端口 if (listen(_sock, 5) == SOCKET_ERROR)//第二个参数为最大等待多少人可以同时连接 { printf("ERROR:监听失败! "); } else { printf("TRUE:监听成功! "); } //3.等待接收客户端连接 sockaddr_in clientAddr = {}; int nAddrLen = sizeof(sockaddr_in); SOCKET _cSOCK = INVALID_SOCKET; char msgBuff[] = "Hello,My is Server! "; while (1) { _cSOCK = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen); if (_cSOCK == INVALID_SOCKET) { printf("ERROR:无效客户端SOCKET! "); } printf("新客户端加入:IP = %s ", inet_ntoa(clientAddr.sin_addr));//inet_ntoa(clientAddr.sin_addr)将接收到的IP地址转化为字符串 //向客户端发送一条数据 send(_cSOCK, msgBuff, strlen(msgBuff) + 1, 0); } //5,关闭自身的socket closesocket(_sock); //WinSocket关闭 WSACleanup(); system("pause"); return 0; }
客户端:
#include<WinSock2.h> #include<Windows.h> #include<stdio.h> #pragma comment(lib,"ws2_32.lib") int main() { WORD ver = MAKEWORD(2, 2); WSADATA dat; WSAStartup(ver, &dat); //建立一个socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == _sock) { printf("ERROR:建立失败! "); } //连接服务器 sockaddr_in _sin = {}; //创建网络地址 _sin.sin_family = AF_INET; _sin.sin_port = htons(4567); //Host to Network Short _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//inet_addr("127.0.0.1"); // IP地址 int ret = connect(_sock, (sockaddr *)&_sin, sizeof(sockaddr_in)); if (SOCKET_ERROR == ret) { printf("ERROR:连接失败! "); } else { printf("连接成功! "); } //接收服务器信息 char recvBuff[256] = {}; int nlen = recv(_sock, recvBuff, 256, 0); if (nlen <= 0) { printf("ERROR:接收失败! "); } else { printf("接收到数据:%s ", recvBuff); } //关闭套接字 closesocket(_sock); //WinSocket启动 WSAStartup(ver, &dat); //WinSocket关闭 WSACleanup(); getchar(); return 0; }