win32_c++_socket
总阅读次
服务器
: 它是被动的,它只能等待别人跟它建立连接,自己不会去主动连接;
[MAKEWORD(2,2)使用][]
[[MAKEWORD(2,2)使用]: http://blog.sina.com.cn/s/blog_a74f39a201010sb3.html
Windows Socket和Linux Socket编程的区别
基础概念
TCP/IP协议族
英语:TCP/IP Protocol Suite,或TCP/IP Protocols),简称TCP/IP
因为该协议家族的两个核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准[3]。由于在网络通讯协议普遍采用分层的结构,当多个层次的协议共同工作时,类似计算机科学中的堆栈,因此又被称为TCP/IP协议栈(英语:TCP/IP Protocol Stack)端口
端口就是特定的程序或者软件也可以理解为特定软件或程序的接口,原端口/目的端口
源端口
就是本机程序用来发送数据的端口,目的端口
就是对方主机用哪个端口接收;封目的端口自己就出不去,封源端口别人就进不来。
数据发送时计算机会在数据段上添上本机端口号(源端口号)和目的主机接收数据的端口号(目的端口号)
数据包通过网络设备走的时候,第一个检查的就是你这个数据包的目的地址在什么地方。
TCP通信3个步骤:
1)建立TCP连接很简单,通过三次握手便可建立连接。
2)建立好连接后,开始传输数据。TCP数据传输牵涉到的概念很多:超时重传、快速重传、流量控制、拥塞控制等等。
3)断开连接的过程也很简单,通过四次握手完成断开连接的过程。TCP三次握手建立连接
第一次握手:客户端发送syn包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。ACK
用于确认资料有无正确的传输到接收端,在ASCII中编号为6网络中进程之间如何通信
网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。侦听端口
服务器倾听端口 ,是服务器监听客户端用的 ,相当于”地址” ,是服务器与客户端间的纽带
TCP/IP首先要有一个服务端
,它是被建立连接的;
WSAStartup
WSAStartup就是为了向操作系统说明,我们要用哪个库文件,让该库文件与当前的应用程序绑定,从而就可以调用该版本的socket的各种函数了。
WSAStartup() - 使用方法
当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。
socket
Windows 下也使用 socket() 函数来创建套接字,原型为:
1 | SOCKET socket(int af, int type, int protocol); |
除了返回值类型不同,其他都是相同的。Windows 不把套接字作为普通文件对待,而是返回 SOCKET 类型的句柄。请看下面的例子:
1 | SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); //创建TCP套接字 |
af 为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。AF 是“Address Family”的简写,INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址,例如 127.0.0.1;AF_INET6 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B。
type 为数据传输方式,常用的有 SOCK_STREAM 和 SOCK_DGRAM,在《socket是什么意思》一节中已经进行了介绍。
- SOCK_STREAM 表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。
- SOCK_DGRAM 表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。
- SOCK_STREAM 表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。
protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。
bind
函数
调用函数 socket 创建套接字描述符时,该套接字描述符是存储在它的协议族空间中,没有具体的地址,要使它与一个地址相关联,可以调用函数bind 使其与地址绑定。客户端的套接字关联的地址一般可由系统默认分配,因此不需要指定具体的地址。若要为服务器端套接字绑定地址,可以通过调用函数 bind 将套接字绑定到一个地址。下面是该函数的描述:
1 | /* 套接字的基本操作 */ |
``SOCKADDR_IN`` 结构体
代码解析
1 |
静态加入一个lib文件
ws2_32.lib文件,提供了对以下网络相关API的支持,若使用其中的API,则应该将ws2_32.lib加入工程(否则需要动态载入ws2_32.dll)。
这句话一般出现在网络编程中,需要使用网络API函数的时候,就必须使用这条语句加载ws2_32.lib库或者动态载入ws2_32.dll
非阻塞套接字
重点参考_TCP Server处理多Client请求的方法—非阻塞accept与select
重点参考_linux下TCP连接的client和server
多线程
fork()
对于主进程 fork()返回新建的子进程ID, 子进程fork()返回0
问题
- 提示:blind fail
尝试解决:
使用
1 | SO_REUSEADDR |
- socket客户端使用recv从服务器`接收数据:有“烫烫”乱码
结论:
TCP中send和recv函数针对的是字符(无边界), 而不是字符串(以’\0’作为边界)。 换句话说, tcp的send和recv函数对所传的内容不敏感, 它关注的是字符, 仅此而已。
recv要做数组初始化,否则会出现烫烫
的乱码
问题代码
1 | recv(sHost, bufRecv,5 , 0); // 接收服务器端的数据, 只接收5个字符 |
方法1.
解决后的代码
手动在recv接受数组添加0作为结束
1 | auto len = recv(sHost, bufRecv, BUF_SIZE, 0); // 接收服务器端的数据, 只接收5个字符 // client4: 读 |
方法2.
在recv前做数组初始化
1 | char bufRecv[100] = { 0 }; |
方法3.
在recv前做清零操作
1 | ZeroMemory(bufRecv, BUF_SIZE); //清0 /*或者这样: memset(bufRecv, 0, BUF_SIZE);*/ |
是不是说char数组没有结尾
\0
输出会出现乱码?server端,send数组明明有
\0
但是client端的rev却没有接收到\0
?
需要了解_c语言——‘\0’,’0’,”0” ,0之间的区别