当前位置: 首页 > news >正文

logo做ppt模板下载网站/站长工具是什么意思

logo做ppt模板下载网站,站长工具是什么意思,淘宝客如何做返积分制网站,网站开发软件培训在谢希仁的《计算机网络》一书中,详尽的学习了网络协议七层塔。也明白了在TCP/IP协议中,可靠性是由传输层来保证的,而传输层的两大协议UDP与TCP,都是在基于网络层IP协议的基础上首次提供端到端的通信。其中,UDP是使用数…

在谢希仁的《计算机网络》一书中,详尽的学习了网络协议七层塔。也明白了在TCP/IP协议中,可靠性是由传输层来保证的,而传输层的两大协议UDP与TCP,都是在基于网络层IP协议的基础上首次提供端到端的通信。其中,UDP是使用数据报提供服务的,而TCP则提供可靠的流服务。UDP提供的是不可靠的服务(相当于篮球运动员,直接将球扔向篮筐,不关注结果),TCP提供的是可靠的服务(投球不中,将一直投,知道投中为止)。在网络传输过程中,TCP的可靠性很大部分是由重传与确认机制来保证的。要了解更多的知识可以看我的下一篇文章《Windows Sockets网络编程(1)TCP select & thread》、也可以去关注一下《Windows Sockets网络编程(2)TCP Stream拆分、拼接》了解更多TCP流分割知识。


目录:

  • How to create a tcp connection
    • client
      • WSAStartup
      • socket
      • sockaddr_in
      • connect
    • server
      • bind
      • listen
      • accept
    • send 与 sendto
    • closesocket
    • WSACleanup
  • client code
  • server code


“谁忽视了TCP,谁注定要推倒重来”——FTP创始人James Van Bokkelen.


How to create a tcp connection

client

WSAStartup

这个函数主要是用来加载Socket库,俩参数,

WSAStartup(_In_ WORD wVersionRequired,_Out_ LPWSADATA lpWSAData);
  • wVersionRequired,指明需要的Socket版本;一般使用宏MAKEWORD(2,2)。

  • lpWSAData,是一个输出变量,指系统实际返回的库信息。

SOCKET _tcp_socket;
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0){perror("WSASartup error !");
}

socket

创建socket,函数原型是这样滴,

socket (_In_ int af,_In_ int type,_In_ int protocol);
  • af 协议族,常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF_ROUTE等。
  • type Socket类型,常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。
    • TCP ,流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。
    • UDP,数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的UDP服务应用。
  • protocol 指定协议,常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

注意:type和protocol不可以随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当第三个参数为0时,会自动选择第二个参数类型对应的默认协议。

_tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (_tcp_socket == INVALID_SOCKET){perror("socket error !");WSACleanup();
}

sockaddr_in

我更喜欢将变量定义为xxx_config,因为在我看来,这很大程度上就相当于一个配置文件,

struct sockaddr_in {short   sin_family;u_short sin_port;struct  in_addr sin_addr;char    sin_zero[8];
};
  • sin_family 地址家族,通常大多用的是都是AF_INET,代表TCP/IP协议族。
  • sin_port 端口,这里必须采用网络数据格式,
    • htons ,将端口号由主机字节序转换为网络字节序的整数值。
  • sin_addr 存储IP地址,这里服务端和客户端是有所区别的。
    • inet_addr 客户端使用,将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。
    • htonl(INADDR_ANY) 服务端使用,INADDR_ANY表示任何IP地址。
SOCKADDR_IN remote_config;
remote_config.sin_port = htons(port);
remote_config.sin_family = AF_INET;
remote_config.sin_addr.S_un.S_addr = inet_addr(addr);

connect

TCP客户端使用它,通过调用connect建立一个连接(虚电路),

int PASCAL FAR connect (_In_ SOCKET s,_In_reads_bytes_(namelen) const struct sockaddr FAR *name,_In_ int namelen);

无需赘言,按照以下方式调用。如果调用失败(SOCKET_ERROR),不要重新调用connect,最好closesocket然后socket重新得到一个新的,继而进行connect。

如果客户端通过WSAGetLastError获得返回值(10061),可能是,

  • 服务端没有运行。
  • IP端口设置有误。

另外,一般UDP客户端不需要调用调用connect,但也并不是不可以。这里,如果调用两次及以上次数connect函数,将造成(10048)错误。

if (connect(_tcp_socket, (sockaddr *)&remote_config, sizeof(remote_config)) == SOCKET_ERROR){perror("connect error !");closesocket(_tcp_socket);WSACleanup();
}

server

bind

作为服务端,必须绑定一个固定的端口,以等待客户端的连接。

int PASCAL FAR bind (_In_ SOCKET s,_In_reads_bytes_(namelen) const struct sockaddr FAR *addr,_In_ int namelen);

这里再次比较一下,客户端与服务端配置文件的写法,

客户端服务端
SOCKADDR_IN remote_config;SOCKADDR_IN local_config;
remote_config.sin_port = htons(port);local_config.sin_port = htons(port);
remote_config.sin_family = AF_INET;local_config.sin_family = AF_INET;
remote_config.sin_addr.S_un.S_addr = inet_addr(addr);local_config.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

特别注意到sin_addr.S_un.S_addr的转换关系,
如果写错了,将导致通信失败。

if (bind(_tcp_socket_listen, (struct sockaddr *)&local_config, sizeof(local_config)) == SOCKET_ERROR){perror("bind error !");closesocket(_tcp_socket_listen);WSACleanup();return;
}

listen

UDP服务端无需做任何准备,因为这一切都市通过sendto/recvfrom建立起来的。但是TCP就不同了,必须使用listen为接纳来自客户端的数据做好准备。

int PASCAL FAR listen (_In_ SOCKET s,_In_ int backlog);
  • backlog,为等待连接的队列长度,也就是当几个客户端同一时间请求时,将放入该队列中,按先后顺序逐个处理。(注意,该参数并不是服务端可接受的最大连接数)。
#define SOMAXCONN       5

系统内部,定义了一个最大正在连接,队列长度数宏SOMAXCONN。

if (listen(_tcp_socket_listen, SOMAXCONN) == SOCKET_ERROR){perror("listen error !");closesocket(_tcp_socket_listen);WSACleanup();return;
}

accept

accept函数,用来接受客户端对服务器发起的连接请求。accept函数牵涉到两个socket,

  • 一个是accept函数的第一个参数(In SOCKET s),这里应该传入的是服务端本身的SOCKET。
  • 二个是accept函数的返回值,它一般代表着新来的客户端SOCKET,除非返回值为SOCKET_ERROR之外。

这里 (struct sockaddr*)&client_config,并不需要服务端自己配置,而是直接填充接收到的客户端的参数。

SOCKET PASCAL FAR accept (_In_ SOCKET s,_Out_writes_bytes_opt_(*addrlen) struct sockaddr FAR *addr,_Inout_opt_ int FAR *addrlen);

正是由于服务端存在多个SOCKET,除了接受到的N个客户端之外,服务端本身还有一个自己的SOCKET,在做善后工作时,记得closesocket服务端本身。

SOCKADDR_IN client_config;
int addr_len = sizeof(client_config);
SOCKET client_tcp_socket = accept(_tcp_socket_listen, (struct sockaddr*)&client_config, &addr_len);
if (client_tcp_socket == SOCKET_ERROR){perror("accept socket error !");break;
}

send 与 sendto

以前,我总是混用,或者是不知其所以然的错误使用这两个函数。正是因为我不知道他们有什么区别,直到我阅读了《Windows Sockets网络编程》一书,

一言蔽之,

  • send 在“TCP”上发送数据。
  • sendto 在“UDP”上发送数据。

注意使用时相互搭配即可,send与recv互补,而sendto与recvfrom是搭档。虽然,send与sendto区别不大,除了以下两点,

  • 所允许的“socket”状态。
  • 从哪里获得“socket”配置。

UDP认为任何socket都是有效的,使用sendto之前不需要做任何准备。而从哪里获取socket配置呢?UDP将sendto中的参数,作为发送数据的目的地址,即使在之前你调用了connect(所以UDP根本不需要调用connect,虽然不会报错)。而TCP恰好相反,如果TCP中使用sendto发送数据,好像也不会报错,但是他会使用connect时的socket配置,而忽略sendto参数中的配置。

正是如此,总是在TCP上使用send/recv。而在UDP上使用sendto/recvfrom。

int Server::sendTcpData(SOCKET* socket, const char* data, const int dataLength){if (data != NULL && *socket != INVALID_SOCKET && dataLength > 0){return send(*socket, data, dataLength, 0);}return 0;
}
  • send返回值, 一般表示实际发送出去的字节数,除非发送失败。
  • recv返回值,一般表示实际接收到的字节数,除非链路异常。
int Server::recvTcpData(SOCKET* socket, char* data, int bufferLength){int ret = 0;if (data != NULL && *socket != INVALID_SOCKET && bufferLength > 0){ret = recv(*socket, data, bufferLength, 0);if (ret > 0){data[ret] = '\0';printf("%s\n", data);}}return ret;
}

closesocket

TCP中,如果需要优雅的关闭,可以去研究一下shutdown函数,粗暴一点就直接调用closesocket吧。(UDP中,应该始终是只调用closesocket。虽然也可以调用shutdown但没有任何意义)。

closesocket函数一般是不会失败的,即使重复调用。因为它只是将socket资源还给协议栈,这里需要注意closesocket函数不是阻塞的,总是一调用直接就返回,不管是真的关闭了。返回值只是表示closesocket该函数有没有调用成功。

如果socket已经成功关闭,再执行任何socket调用,都会得到(10038)错误。

WSACleanup

与WSAStartup是孪生兄弟,用于加载套接字DLL库,让所有socket函数可以有效(无效)的调到,一般只需要调用一次即可。

  • WSAStartup 加载套接字库。
  • WSACleanup 卸载套接字库,释放所有资源,后续所有socket都会失效。

这两个函数,一般不会失败。

client code

client.h

#pragma once#include <windows.h>
#pragma comment(lib,"ws2_32.lib") class Client
{
public:Client(char* addr, int port);~Client();int sendTcpData(const char* data, const int dataLength);int recvTcpData(char* data, int bufferLength);
private:SOCKET _tcp_socket;
};

client.cpp

#include "Client.h"
#include <stdio.h>Client::Client(char* addr, int port)
{WSADATA wsa;if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0){perror("WSASartup error !");return;}_tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (_tcp_socket == INVALID_SOCKET){perror("socket error !");WSACleanup();return;}SOCKADDR_IN remote_config;remote_config.sin_port = htons(port);remote_config.sin_family = AF_INET;remote_config.sin_addr.S_un.S_addr = inet_addr(addr);if (connect(_tcp_socket, (sockaddr *)&remote_config, sizeof(remote_config)) == SOCKET_ERROR){perror("connect error !");closesocket(_tcp_socket);WSACleanup();return;}
}Client::~Client()
{if (_tcp_socket != INVALID_SOCKET){if(closesocket(_tcp_socket) == 0){_tcp_socket = INVALID_SOCKET;WSACleanup();return;}perror("close socket error.");}
}int Client::sendTcpData(const char* data, const int dataLength){if (data != NULL && _tcp_socket != INVALID_SOCKET && dataLength > 0){return send(_tcp_socket, data, dataLength, 0);}return 0;
}int Client::recvTcpData(char* data, int bufferLength){int ret = 0;if (data != NULL && _tcp_socket != INVALID_SOCKET && bufferLength > 0){ret = recv(_tcp_socket, data, bufferLength, 0);if (ret > 0){data[ret] = '\0';printf("%s\n",data);}}return ret;
}int main(){Client c("127.0.0.1", 8086);char* strNum = "1234567890";c.sendTcpData(strNum, strlen(strNum));char recv[1024];c.recvTcpData(recv, sizeof(recv));char* strStr = "abcdefghi";c.sendTcpData(strStr, strlen(strStr));c.recvTcpData(recv, sizeof(recv));return 0;
}

server code

server.h

#pragma once#include <windows.h>
#pragma comment(lib,"ws2_32.lib") class Server
{
public:Server(int port);~Server();void acceptTcpSocket();int sendTcpData(SOCKET* socket, const char* data, const int dataLength);int recvTcpData(SOCKET* socket, char* data, int bufferLength);
private:SOCKET _tcp_socket_listen;
};

server.cpp

#include "Server.h"
#include <stdio.h>Server::Server(int port)
{WSADATA wsa;if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0){perror("WSASartup error !");return;}_tcp_socket_listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (_tcp_socket_listen == INVALID_SOCKET){perror("socket error !");WSACleanup();return;}SOCKADDR_IN local_config;local_config.sin_port = htons(port);local_config.sin_family = AF_INET;local_config.sin_addr.S_un.S_addr = htonl(INADDR_ANY);if (bind(_tcp_socket_listen, (struct sockaddr *)&local_config, sizeof(local_config)) == SOCKET_ERROR){perror("bind error !");closesocket(_tcp_socket_listen);WSACleanup();return;}if (listen(_tcp_socket_listen, SOMAXCONN) == SOCKET_ERROR){perror("listen error !");closesocket(_tcp_socket_listen);WSACleanup();return;}
}Server::~Server()
{if (_tcp_socket_listen != INVALID_SOCKET){if (closesocket(_tcp_socket_listen) == 0){_tcp_socket_listen = INVALID_SOCKET;WSACleanup();return;}perror("close socket error.");}
}void Server::acceptTcpSocket(){bool flag = true;while (flag){SOCKADDR_IN client_config;int addr_len = sizeof(client_config);SOCKET client_tcp_socket = accept(_tcp_socket_listen, (struct sockaddr*)&client_config, &addr_len);if (client_tcp_socket == SOCKET_ERROR){perror("accept socket error !");break;}while (flag){char recv[1024];if (recvTcpData(&client_tcp_socket, recv, sizeof(recv)) <= 0){perror("recv error !");break;}char* data = "Hi, I'm William Aiden !";if (sendTcpData(&client_tcp_socket, data, strlen(data)) <= 0){perror("send error !");break;}}}
}int Server::sendTcpData(SOCKET* socket, const char* data, const int dataLength){if (data != NULL && *socket != INVALID_SOCKET && dataLength > 0){return send(*socket, data, dataLength, 0);}return 0;
}int Server::recvTcpData(SOCKET* socket, char* data, int bufferLength){int ret = 0;if (data != NULL && *socket != INVALID_SOCKET && bufferLength > 0){ret = recv(*socket, data, bufferLength, 0);if (ret > 0){data[ret] = '\0';printf("%s\n", data);}}return ret;
}int main(){Server s(8086);s.acceptTcpSocket();return 0;
}
http://www.jmfq.cn/news/4881763.html

相关文章:

  • php语言 网站建设/网络推广技术外包
  • 网站建设与管理就业/网站快速优化排名推荐
  • 杭州专业网站制作设计/百度入口的链接
  • 婚纱摄影手机网站欣赏/市场策划方案
  • 做pc端网站行情/sem是什么方法
  • 怎么做企业的网站/发布任务注册app推广的平台
  • 深圳市浩天建设网站/江阴网站制作公司
  • 网站开发的职业规划/最近的新闻大事
  • 制冷机电工程东莞网站建设/北京出大大事了
  • 做鞋子出口需要作网站吗/国内最新十大新闻
  • 基于html5的旅游网站的设计/营销策略主要包括哪些
  • 手机网站弹窗/培训网站推荐
  • 做效果图兼职的网站有哪些/权重查询
  • 没有公司网站如何做推广/百度100%秒收录
  • 怎么给钓鱼网站做防红/seo排名优化排行
  • 桂阳局网站建设方案/360安全网址
  • 政协信息化网站建设的请示/电商网站订烟平台
  • 网页设计代写价格/西安关键词seo公司
  • 众筹网站建设需要多少资金/手机怎么建立网站
  • 网站建设原则应考虑哪些内容/网络营销工具有哪些
  • 网站功能需求文档/怎样给自己的网站做优化
  • 做pc和移动网站的适配/网站优化公司哪家好
  • 上海网站建设哪家服务好/企业网站建设的流程
  • 网站外链建设工作总结/百度竞价软件哪个好
  • 虚拟展馆官方网站建设/上百度推广的网站要多少钱
  • 深圳正规网站制作哪里好/哪里有正规的电商培训班
  • 网站后台 js框架/南昌网优化seo公司
  • 网站开发协义/培训机构网站模板
  • 广告推广网站建设/百度人工在线客服
  • 微信开放平台网站应用/站外推广平台有哪些