socket编程教程_C语言中文网

代码参考socket

sokect原理参考

服务器: 它是被动的,它只能等待别人跟它建立连接,自己不会去主动连接;

原理:使用SOCKET实现TCP/IP协议的通讯

参考资料_什么是原端口和目的端口

基本TCP套接字编程讲解_流程图

图解TCP-IP协议

Socket详解

[MAKEWORD(2,2)使用][]

什么叫“低八位、高八位;低四位、高四位”

[c++中冒号(:)和双冒号(::)的用法 ][]

Windows Socket和Linux Socket编程的区别

C++使用thread类多线程编程


基础概念

  1. TCP/IP协议族

    英语:TCP/IP Protocol Suite,或TCP/IP Protocols),简称TCP/IP
    因为该协议家族的两个核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准[3]。由于在网络通讯协议普遍采用分层的结构,当多个层次的协议共同工作时,类似计算机科学中的堆栈,因此又被称为TCP/IP协议栈(英语:TCP/IP Protocol Stack)

  1. 端口
    端口就是特定的程序或者软件也可以理解为特定软件或程序的接口,

  2. 原端口/目的端口
    源端口就是本机程序用来发送数据的端口,目的端口就是对方主机用哪个端口接收;

    封目的端口自己就出不去,封源端口别人就进不来。

数据发送时计算机会在数据段上添上本机端口号(源端口号)和目的主机接收数据的端口号(目的端口号)
数据包通过网络设备走的时候,第一个检查的就是你这个数据包的目的地址在什么地方。

  1. TCP通信3个步骤:
    1)建立TCP连接很简单,通过三次握手便可建立连接。
    2)建立好连接后,开始传输数据。TCP数据传输牵涉到的概念很多:超时重传、快速重传、流量控制、拥塞控制等等。
    3)断开连接的过程也很简单,通过四次握手完成断开连接的过程。
  1. 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状态,完成三次握手。
  1. ACK
    用于确认资料有无正确的传输到接收端,在ASCII中编号为6

  2. 网络中进程之间如何通信
    网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

  1. 侦听端口
    服务器倾听端口 ,是服务器监听客户端用的 ,相当于”地址” ,是服务器与客户端间的纽带

TCP/IP首先要有一个服务端,它是被建立连接的;


  • WSAStartup

WSAStartup就是为了向操作系统说明,我们要用哪个库文件,让该库文件与当前的应用程序绑定,从而就可以调用该版本的socket的各种函数了。

WSAStartup解释1

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套接字
  1. 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。
  1. type 为数据传输方式,常用的有 SOCK_STREAM 和 SOCK_DGRAM,在《socket是什么意思》一节中已经进行了介绍。

    1) SOCK_STREAM 表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。

    2) SOCK_DGRAM 表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。

  1. protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。
  • bind 函数

调用函数 socket 创建套接字描述符时,该套接字描述符是存储在它的协议族空间中,没有具体的地址,要使它与一个地址相关联,可以调用函数bind 使其与地址绑定。客户端的套接字关联的地址一般可由系统默认分配,因此不需要指定具体的地址。若要为服务器端套接字绑定地址,可以通过调用函数 bind 将套接字绑定到一个地址。下面是该函数的描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* 套接字的基本操作 */   
/*
* 函数功能:将协议地址绑定到一个套接字;其中协议地址包含IP地址和端口号;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*
* 说明:
* sockfd 为套接字描述符;
* addr是一个指向特定协议地址结构的指针;
* addrlen是地址结构的长度;
*/
```




+ ``SOCKADDR_IN`` 结构体

[sockaddr_in结构体简介][]

[sockaddr_in结构体简介]: http://blog.chinaunix.net/uid-20673616-id-1578732.html











# 代码解析

#pragma comment(lib, “ws2_32.lib”)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

静态加入一个lib文件

ws2_32.lib文件,提供了对以下网络相关API的支持,若使用其中的API,则应该将ws2_32.lib加入工程(否则需要动态载入ws2_32.dll)。
这句话一般出现在网络编程中,需要使用网络API函数的时候,就必须使用这条语句加载ws2_32.lib库或者动态载入ws2_32.dll













# 非阻塞套接字


[参考_Windows Socket 非阻塞模式开发][]

[参考_Windows Socket 非阻塞模式开发]: http://blog.csdn.net/ithzhang/article/details/8274596




[socket同步/异步通信] []



[socket同步/异步通信]: http://www.it610.com/article/5036113.htm


[重点参考_TCP Server处理多Client请求的方法—非阻塞accept与select][]

[重点参考_TCP Server处理多Client请求的方法—非阻塞accept与select]: http://velep.com/archives/1137.html



[重点参考_linux下TCP连接的client和server][]

[重点参考_linux下TCP连接的client和server]: http://blog.csdn.net/linuxheik/article/details/19326469




[可参考代码_C++多线程socket系统新编][]

[可参考代码_C++多线程socket系统新编]: http://blog.csdn.net/wyansai/article/details/50762479

## 多线程




[参考代码_C++多线程socket系统新编][]


[参考代码_C++多线程socket系统新编]: http://blog.csdn.net/wyansai/article/details/50762479



[Socket编程模型之简单选择模型][]


[Socket编程模型之简单选择模型]: http://blog.csdn.net/caoshiying/article/details/52550761





[使用Cout输出String和CString对象][]


[使用Cout输出String和CString对象]: http://www.cnblogs.com/hushaojun/p/4920151.html


[ C++基础::为什么不能cout一个string?][]


[ C++基础::为什么不能cout一个string?]: http://blog.csdn.net/lanchunhui/article/details/49757713



[ C++中的C_str()函数用法][]

[ C++中的C_str()函数用法]: http://blog.csdn.net/nancy_m/article/details/7583550








fork()

对于主进程 fork()返回新建的子进程ID, 子进程fork()返回0


[fork()函数详解 ][]


[fork()函数详解 ]: http://blog.chinaunix.net/uid-26495963-id-3150116.html





# 问题

+ 提示:blind fail

尝试解决:

使用

SO_REUSEADDR

1
2
3
4
5
6
7
8
9
10
11
12
13
14



+ socket客户端使用recv从服务器`接收数据:有“烫烫”乱码


结论:
TCP中send和recv函数针对的是字符(无边界), 而不是字符串(以'\0'作为边界)。 换句话说, tcp的send和recv函数对所传的内容不敏感, 它关注的是字符, 仅此而已。
recv要做数组初始化,否则会出现``烫烫``的乱码




问题代码

  recv(sHost, bufRecv,5 , 0);     // 接收服务器端的数据, 只接收5个字符  
    cout << endl <<"从服务器接收数据:" << bufRecv;  
}  
//退出 
1
2
3
4
5

方法1.

解决后的代码
手动在recv接受数组添加0作为结束
    auto len = recv(sHost, bufRecv, BUF_SIZE, 0);     // 接收服务器端的数据, 只接收5个字符            // client4:  读
    bufRecv[len] = 0;
    cout << endl << "从服务器`接收数据:" << bufRecv;
}
//退出 
1
2
3
4
5


方法2.

在recv前做数组初始化

char bufRecv[100] = { 0 };
 recv(sHost, bufRecv, 100, 0);
1
2
3
4


方法3.
在recv前做清零操作

ZeroMemory(bufRecv, BUF_SIZE);  //清0   /*或者这样:    memset(bufRecv, 0, BUF_SIZE);*/
 recv(sHost, bufRecv, BUF_SIZE, 0);

```

  1. 是不是说char数组没有结尾\0输出会出现乱码?
  1. server端,send数组明明有\0但是client端的rev却没有接收到\0

需要了解_c语言——‘\0’,’0’,”0” ,0之间的区别

需要了解_字符和字符字面值

CSDN类似问题

District 9(2009

  1. typename
    “typename”是一个C++程序设计语言中的关键字。当用于泛型编程时是另一术语”class”的同义词。[1]这个关键字用于指出模板声明(或定义)中的非独立名称(dependent names)是类型名,而非变量名。以下是对于泛型编程中typename两种迥然不同的用法的解释。

Fork me on GitHub