余姚 网站建设,想在百度上推广怎么做,外包做网站哪家好,如何编写app软件今天开始进入Windows网络编程的学习#xff0c;在学习的时候总是陷入Windows复杂的参数#xff0c;纠结于这些。从老师的讲解中#xff0c;这些内容属于是定式#xff0c;主要学习写的逻辑。给自己提个醒#xff0c;要把精力放在正确的位置#xff0c;不要无端耗费精力。… 今天开始进入Windows网络编程的学习在学习的时候总是陷入Windows复杂的参数纠结于这些。从老师的讲解中这些内容属于是定式主要学习写的逻辑。给自己提个醒要把精力放在正确的位置不要无端耗费精力。 关于C/S模式
CClient 客户端
打开一个通信通道并连接到服务器所在主机的特定端口向服务器发服务请求等待并接收应答继续提出请求请求结束后关闭通信通道并终止 SServer 服务端
首先服务器先启动并根据请求提供相应的服务打开一个通信通道在某一地址和端口上接收请求等待客户请求到达该端口接收到服务请求处理该请求并发送应答信号返回第二步等待另一客户请求关闭服务器 关于TCP与UDP
TCP面向连接的套接字
传输过程中数据不会丢失按顺序传输数据传输的过程中不存在数据边界
UDP面向消息的套接字
强调快速传输而非顺序传输的数据可能丢失也可能损毁限制每次传输数据的大小传输的数据由数据边界 关于IP
是分配给用户上网使用的网际协议
常见的IP地址分为IPv4与IPv6两大类两大类 关于端口
为区分程序中创建的套接字而分配给套接字的序号
不同的端口对应不同的应用程序
端口有65536之多 关于套接字类型与协议设置
SOCK_STREAM 对应TCP协议
SOCK_DGRAM 对应UDP
SOCK_RAW 可以读写内核没有处理的IP数据包避开 TCP/IP 处理机制被传送的数据报可以被直接传送给需要它的的应用程序 关于网络编程的基本函数和基本数据结构 两个重要的数据结构
struct sockaddr {u_short sa_family; //16 位地址类型 2 字节char sa_data[14]; //14 字节地址数据ip port
};
struct sockaddr_in {short sin_family; //16 位地址类型u_short sin_port; //16 位端口号 65535 2 的 16 次方struct in_addr sin_addr; //32 位 IP 地址 4 字节char sin_zero[8]; //8 字节填充
}; TCP 套接字 TCP Server
代码如下
#include stdio.h
#include stdlib.h
#include WinSock2.h// error LNK2019: 无法解析的外部符号 __imp__accept12函数 _main 中引用了该符号
#pragma comment(lib,ws2_32.lib) // 导入库int main()
{printf(TCP Server\n);// 0. 初始化网络库 加载套接字库 这是个标准做法直接拷贝即可WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested MAKEWORD(2, 2);// 1、初始化套接字库err WSAStartup(wVersionRequested, wsaData);if (err ! 0){printf(WSAStartup errorNum %d\n, GetLastError());return err;}if (LOBYTE(wsaData.wVersion) ! 2 || HIBYTE(wsaData.wVersion) ! 2){printf(LOBYTE errorNum %d\n, GetLastError());WSACleanup();return -1;}// 1. 安装电话机// AF_INET指定了使用 IPv4 地址和 TCP/IP 协议栈进行网络通信。// 用于指定套接字的类型表示基于流的传输协议常用于 TCP 协议的网络通信。// 第三个参数由前两个决定。// 光标放在socket()函数上摁下F1转到官方文档SOCKET sockSrv socket(AF_INET,SOCK_STREAM,0); //socket 函数创建一个绑定到特定传输服务提供者的套接字。if (INVALID_SOCKET sockSrv){printf(socket errorNum %d\n, GetLastError());return -1;}// 2. 分配电话号码填充参数SOCKADDR_IN addSrv; // SOCKADDR_IN结构指定 AF_INET 地址系列的传输地址和端口。// 设置为任何IPaddSrv.sin_addr.S_un.S_addr htonl(INADDR_ANY);addSrv.sin_family AF_INET;addSrv.sin_port htons(6000);// 根据官方文档这里需要强转 if (SOCKET_ERROR bind(sockSrv, (SOCKADDR*)addSrv, sizeof(SOCKADDR))) // 绑定函数将本地地址与套接字相关联。{printf(bind errorNum %d\n, GetLastError());return -1;}// 3. 监听 listen// 将套接字置于侦听传入连接的状态。if (SOCKET_ERROR listen(sockSrv, 5)){printf(listen errorNum %d\n, GetLastError());return -1;}SOCKADDR_IN addrCli;int len sizeof(SOCKADDR);while (true){// 4.分配一台分机去处理客户端的连接printf(begin accept: \n);SOCKET sockConn accept(sockSrv,(SOCKADDR*)addrCli,len);printf(end accept: \n);char sendBuf[100] { 0 };sprintf_s(sendBuf, 100, Welcome %s to bingo!,inet_ntoa(addrCli.sin_addr));int iLen send(sockConn,sendBuf,strlen(sendBuf),0);char recvBuf[100] { 0 };iLen recv(sockConn, recvBuf, 100, 0);printf(recvBuf %s\n, recvBuf);// 关闭分机closesocket(sockConn);}// 关闭总机closesocket(sockSrv);WSACleanup();system(pause);return 0;
} TCP Client
代码如下
#include WinSock2.h
#include stdio.h
#include stdlib.h
#pragma comment(lib, ws2_32.lib)int main()
{printf(Client\n);char sendBuf[] hello,world;//1 初始化网络库// 加载套接字库WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested MAKEWORD(2, 2);// 1、初始化套接字库err WSAStartup(wVersionRequested, wsaData);if (err ! 0){printf(WSAStartup errorNum %d\n, GetLastError());return err;}if (LOBYTE(wsaData.wVersion) ! 2 || HIBYTE(wsaData.wVersion) ! 2){printf(LOBYTE errorNum %d\n, GetLastError());WSACleanup();return -1;}// 2 安装电话机// 新建套接字SOCKET sockCli socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET sockCli){printf(socket errorNum %d\n, GetLastError());return -1;}SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr inet_addr(10.134.142.81);addrSrv.sin_family AF_INET;addrSrv.sin_port htons(6000);// 3 连接服务器if (SOCKET_ERROR connect(sockCli, (SOCKADDR*)addrSrv, sizeof(SOCKADDR))){printf(connect errorNum %d\n, GetLastError());return -1;}// 4 接收和发送数据char recvBuf[100] { 0 };int iLen recv(sockCli, recvBuf, 100, 0);if (iLen 0){printf(recv errorNum %d\n, GetLastError());return -1;}printf(Client recvBuf %s\n, recvBuf);// 发送数据iLen send(sockCli, sendBuf, strlen(sendBuf) 1, 0);if (iLen 0){printf(send errorNum %d\n, GetLastError());return -1;}// 关闭套接字closesocket(sockCli);WSACleanup();system(pause);return 0;
}// 报错严重性 代码 说明 项目 文件 行 禁止显示状态
// 错误 C4996 inet_addr: Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings TCP Client C : \Users\mi\Desktop\Code - C\MyNetPro\TCP Client\TCP Client.cpp 38
// 我们需要把它 _WINSOCK_DEPRECATED 忽略掉 工程属性 C预处理器添加即可结果如下 关于Listen()
listen(sockSrv,5)这个函数是规定了消息队列最多可以有五个后面再来的消息会来连接不上。 关于VS的启动项
设置哪个为启动项就会编译那个过程的C文件 关于报错 _WINSOCK_DEPRECATED // 报错严重性 代码 说明 项目 文件 行 禁止显示状态 // 错误 C4996 inet_addr: Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings TCP Client C : \Users\mi\Desktop\Code - C\MyNetPro\TCP Client\TCP Client.cpp 38 // 我们需要把它 _WINSOCK_DEPRECATED 忽略掉 工程属性 C预处理器添加即可 优化recv与send解决超大数据传输问题
接收端
int MySocketRecv0(int sock, char* buf, int dateSize)
{//循环接收int numsRecvSoFar 0; // 目前受到的数据int numsRemainingToRecv dateSize; // 剩余要收的数据printf(enter MySocketRecv0\n);while (1){int bytesRead recv(sock, buf[numsRecvSoFar], numsRemainingToRecv, 0);printf(###bytesRead %d,numsRecvSoFar %d, numsRemainingToRecv %d\n,bytesRead, numsRecvSoFar, numsRemainingToRecv);if (bytesRead numsRemainingToRecv) // 一次性完全接收{return 0;}else if (bytesRead 0) // 未接收完更新已接受数据和未接受数据{numsRecvSoFar bytesRead;numsRemainingToRecv - bytesRead;continue;}else if ((bytesRead 0) (errno EAGAIN)){continue;}else{return -1;}}
}
发送端
int MySocketSend0(int socketNum, unsigned char* data, unsigned dataSize)
{unsigned numBytesSentSoFar 0;unsigned numBytesRemainingToSend dataSize;while (1){int bytesSend send(socketNum, (char const*)(data[numBytesSentSoFar]),numBytesRemainingToSend, 0/*flags*/);if (bytesSend numBytesRemainingToSend){return 0;}else if (bytesSend 0){numBytesSentSoFar bytesSend;numBytesRemainingToSend - bytesSend;continue;}else if ((bytesSend 0) (errno 11)){continue;}else{return -1;}}
}