├── .gitignore ├── LICENSE ├── README.md ├── daytime服务 ├── C++版 │ ├── daytimetcpcli.c │ └── daytimetcpsrv.c ├── java版 │ └── daytime.java └── python版 │ ├── 本地服务器(TCP) │ ├── daytimeClient.py │ └── daytimeServer.py │ └── 远程服务器 │ ├── __init__.py │ └── daytime.py ├── echo服务 └── select实现并发 │ ├── client.py │ └── server.py ├── 《计算机网络自顶向下方法》课后编程作业题解 └── 第二章(应用层) │ ├── 作业1:Web服务器 │ ├── WebClient.py │ ├── WebServer.py │ ├── __init__.py │ ├── index.html │ ├── response.html │ └── test.py │ ├── 作业2:UDP ping程序 │ ├── UDPPingClient.py │ ├── UDPPingServer.py │ └── __init__.py │ ├── 作业3:邮件客户 │ ├── SmtpDemo.py │ └── __init__.py │ └── 扩展1:TCP ping程序 │ ├── TCPPingClient.py │ ├── TCPPingServer.py │ └── __init__.py └── 计算机通信网实验 ├── exp01 ├── python版 │ ├── client.py │ ├── logger.py │ └── server.py └── windows c++版 │ ├── client.cpp │ ├── readme.md │ └── server.cpp └── exp02 ├── client.py ├── constant.py ├── fortest ├── __init__.py ├── t2.py ├── t3.py └── test.py ├── server.py └── util.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ComputerNetwork 2 | :dolphin:计算机网络学习代码,主要采用python/java实现 3 | 4 | -------------------------------------------------------------------------------- /daytime服务/C++版/daytimetcpcli.c: -------------------------------------------------------------------------------- 1 | #include "unp.h" 2 | 3 | int 4 | main(int argc, char **argv) 5 | { 6 | int sockfd, n; 7 | char recvline[MAXLINE + 1]; 8 | struct sockaddr_in servaddr; 9 | 10 | if (argc != 2) 11 | err_quit("usage: a.out "); 12 | 13 | if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 14 | err_sys("socket error"); 15 | 16 | bzero(&servaddr, sizeof(servaddr)); 17 | servaddr.sin_family = AF_INET; 18 | servaddr.sin_port = htons(13); /* daytime server */ 19 | if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) 20 | err_quit("inet_pton error for %s", argv[1]); 21 | 22 | if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) 23 | err_sys("connect error"); 24 | 25 | while ( (n = read(sockfd, recvline, MAXLINE)) > 0) { 26 | recvline[n] = 0; /* null terminate */ 27 | if (fputs(recvline, stdout) == EOF) 28 | err_sys("fputs error"); 29 | } 30 | if (n < 0) 31 | err_sys("read error"); 32 | 33 | exit(0); 34 | } 35 | -------------------------------------------------------------------------------- /daytime服务/C++版/daytimetcpsrv.c: -------------------------------------------------------------------------------- 1 | #include "unp.h" 2 | #include 3 | 4 | int 5 | main(int argc, char **argv) 6 | { 7 | int listenfd, connfd; 8 | struct sockaddr_in servaddr; 9 | char buff[MAXLINE]; 10 | time_t ticks; 11 | 12 | listenfd = Socket(AF_INET, SOCK_STREAM, 0); 13 | 14 | bzero(&servaddr, sizeof(servaddr)); 15 | servaddr.sin_family = AF_INET; 16 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 17 | servaddr.sin_port = htons(13); /* daytime server */ 18 | 19 | Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 20 | 21 | Listen(listenfd, LISTENQ); 22 | 23 | for ( ; ; ) { 24 | connfd = Accept(listenfd, (SA *) NULL, NULL); 25 | 26 | ticks = time(NULL); 27 | snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); 28 | Write(connfd, buff, strlen(buff)); 29 | 30 | Close(connfd); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /daytime服务/java版/daytime.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Ubuntu下编写自己的DAYTIME客户端,并在互联网上找一个DAYTIME服务器连接, 3 | * 验证结果,打印代码和运行的输出结果。 4 | * www.unpbook.com 5 | */ 6 | 7 | import java.io.*; 8 | import java.net.*; 9 | public class daytimetest { 10 | 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | // TODO Auto-generated method stub 16 | String sHostName; 17 | /* 18 | * Get the name of the server from the command line. No entry,use 19 | * tock.usno.navy.mil 20 | */ 21 | if(args.length>0){ 22 | sHostName = args[0]; 23 | } 24 | else{ 25 | //"www.time.ac.cn" 或 "time.nist.gov" 26 | sHostName = "time.nist.gov"; 27 | } 28 | /* 29 | * Opeb a socket to port 13. Prepare to receive the Daytime information. 30 | */ 31 | try{ 32 | Socket oSocket = new Socket(sHostName,13); 33 | InputStream oTimeStream =oSocket.getInputStream(); 34 | StringBuffer oTime = new StringBuffer(); 35 | 36 | // Fetch the Daytime information. 37 | int iCharacter; 38 | while((iCharacter = oTimeStream.read()) != -1){ 39 | oTime.append((char)iCharacter); 40 | } 41 | // Convert Daytime to a String and output. 42 | String sTime = oTime.toString().trim(); 43 | System.out.println("It's:" + sTime + "at " + sHostName + "."); 44 | oTimeStream.close(); 45 | oSocket.close(); 46 | 47 | }catch (UnknownHostException e){ 48 | System.err.print(e); 49 | }catch (IOException e){ 50 | System.err.print(e); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /daytime服务/python版/本地服务器(TCP)/daytimeClient.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | serverName = '127.0.0.1' # 主机 3 | serverPort = 12000 4 | 5 | clientSocket = socket(AF_INET, SOCK_STREAM) 6 | clientSocket.connect((serverName,serverPort)) 7 | 8 | print(clientSocket.recv(1024).decode()) 9 | -------------------------------------------------------------------------------- /daytime服务/python版/本地服务器(TCP)/daytimeServer.py: -------------------------------------------------------------------------------- 1 | import time 2 | from socket import * 3 | serverSocket = socket(AF_INET, SOCK_STREAM) 4 | serverSocket.bind(('127.0.0.1',12000)) 5 | 6 | serverSocket.listen(1) 7 | 8 | while True: 9 | 10 | connectionSocket, address = serverSocket.accept() 11 | serverTime = time.time() 12 | sendTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(serverTime)) 13 | message = "Server time :" + sendTime 14 | connectionSocket.send(message.encode()) 15 | connectionSocket.close() 16 | -------------------------------------------------------------------------------- /daytime服务/python版/远程服务器/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspurer/ComputerNetwork/400ee895746e34687094e0a4cb28b5c0b21e7f94/daytime服务/python版/远程服务器/__init__.py -------------------------------------------------------------------------------- /daytime服务/python版/远程服务器/daytime.py: -------------------------------------------------------------------------------- 1 | import socket 2 | HOST = "time.nist.gov" 3 | PORT = 13 4 | client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 5 | try: 6 | client.connect((HOST,PORT)) 7 | data = client.recv(1024) 8 | #字节转字符串 9 | time = str(data,encoding='utf-8') 10 | print("the server's time is:",time) 11 | except Exception as e: 12 | print('Error!') -------------------------------------------------------------------------------- /echo服务/select实现并发/client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/9 5 | # file_name: client.py 6 | # description: 月小水长,热血未凉 7 | 8 | from socket import * 9 | 10 | if __name__ == "__main__": 11 | serverName = '127.0.0.1' 12 | serverPort = 13000 13 | clientSocket = socket(AF_INET, SOCK_STREAM) 14 | clientSocket.connect((serverName, serverPort)) 15 | while True: 16 | echoMessage = input("请输入:") 17 | clientSocket.send(echoMessage.encode("utf-8")) 18 | print("来自服务端的应答",clientSocket.recv(1024).decode("utf-8")) 19 | #发出关闭连接命令,服务端收到并回复后立即关闭 20 | if echoMessage.upper() == "BYE": 21 | break -------------------------------------------------------------------------------- /echo服务/select实现并发/server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/9 5 | # file_name: server.py 6 | # description: 月小水长,热血未凉 7 | 8 | from socket import * 9 | import select 10 | 11 | def echoHandler(connectionSocket,rList): 12 | try: 13 | echoMessage = connectionSocket.recv(1024) 14 | connectionSocket.send(echoMessage) 15 | if echoMessage.decode("utf-8").upper() == "BYE": 16 | print("客户端",connectionSocket.getsockname(),"已断开连接") 17 | rList.remove(connectionSocket) 18 | connectionSocket.close() 19 | except: 20 | pass 21 | if __name__ == "__main__": 22 | # 创建服务套接字 23 | # AF_INE指明是ipv4,如果指明要ipv6需要使用AF_INET 24 | # SOCK_STREAM指明是基于TCP,如果基于UDP需要使用SOCK_DGRAM 25 | serverSocket = socket(AF_INET, SOCK_STREAM) 26 | # 将服务套接字绑定到本机的12000号端口 27 | serverSocket.bind(('127.0.0.1', 13000)) 28 | 29 | 30 | # 最大连接数为10 31 | serverSocket.listen(10) 32 | #服务套接字接收客户端的连接请求,并返回连接套接字和地址 33 | # windows下python禁用fork(),所以我采用select 34 | 35 | rList = [serverSocket] # 可读描述符列表 36 | wList = [] # 可写描述符列表 37 | eList = [] # 错误描述符列表 38 | 39 | print("等待客户端连接......") 40 | while True: 41 | """ 42 | select(),有4个参数,前三个必须也就是感兴趣的描述符,第四个是超时时间 43 | 第一个参数:可读描述符列表 44 | 第二个参数:可写描述符列表 45 | 第三个参数:错误信息描述符列表 46 | 对于自己的套接字来说,输入表示可以读取,输出表示可以写入,套接字就相当于一个管道,对方的写入代表你的读取,你的写入代表对方的读取 47 | 48 | select函数返回什么呢?你把感兴趣的描述符加入到列表中并交给select后,当有可读或者有可写或者错误这些描述符就绪后,select就会返回 49 | 哪些就绪的描述符,你需要做的就是遍历这些描述符逐一进行处理。 50 | """ 51 | readSet, writeSet, errorSet = select.select(rList, wList, eList) 52 | 53 | # 处理描述符可读 54 | for readAbledSockFD in readSet: 55 | if readAbledSockFD is serverSocket: 56 | try: 57 | # 因为 select的机理,这里的accept永远不会阻塞,因为是客户端有请求链接,severSocket才会进可读列表 58 | connFd, remAddr = serverSocket.accept() 59 | except Exception as err: 60 | """ 61 | 这里处理当三次握手完成后,客户端意外发送了一个RST,这将导致一个服务器错误 62 | """ 63 | print("RST错误") 64 | continue 65 | print("新连接:", connFd.getpeername()) 66 | # 把新连接加入可读列表中 67 | rList.append(connFd) 68 | else: 69 | echoHandler(readAbledSockFD, rList) 70 | 71 | # 处理描述符可写 72 | for writeAbledSockFd in writeSet: 73 | pass 74 | 75 | # 处理错误描述符 76 | for errAbled in errorSet: 77 | pass 78 | pass -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业1:Web服务器/WebClient.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | ClientSocket = socket(AF_INET, SOCK_STREAM) 3 | ClientSocket.connect(('localhost',9999)) 4 | while True: 5 | #这里的Connetction: close不同于浏览器常见的keep-alive, 6 | #close表示要求服务器在发送完被请求的对象后就关闭这条链接 7 | Head = '''GET /index.html HTTP/1.1\r\nHost: localhost:9999\r\nConnection: close\r\nUser-agent: Mozilla/5.0\r\n\r\n''' 8 | ClientSocket.send(Head.encode('utf-8')) 9 | data = ClientSocket.recv(1024) 10 | print(data) 11 | with open("response.html","wb") as f: 12 | f.write(data) 13 | 14 | 15 | -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业1:Web服务器/WebServer.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | serverSocket = socket(AF_INET, SOCK_STREAM) 3 | serverSocket.bind(("127.0.0.1",9999)) 4 | serverSocket.listen(1) 5 | # 没有客户端链接时一直在此阻塞 6 | connectionSocket, addr = serverSocket.accept() 7 | while True: 8 | print('waiting for connection...') 9 | try: 10 | #接收1k数据 11 | data = connectionSocket.recv(1024) 12 | print(data) 13 | if not data: 14 | continue 15 | #data是一个get的http请求报文 16 | filename = data.split()[1] #filename = /HelloWorld.html 17 | # #print(filename[1:]) 18 | f = open(filename[1:],encoding="utf-8") #f = HelloWorld.html 19 | outputdata = f.read() 20 | header = 'HTTP/1.1 200 OK\r\n\r\n' 21 | #回复报文 22 | connectionSocket.send(header.encode()) 23 | for i in range(0, len(outputdata)): 24 | connectionSocket.send(outputdata[i].encode()) 25 | 26 | except IOError: 27 | header = 'HTTP/1.1 404 NOT FOUND\r\n\r\n' 28 | connectionSocket.send(header.encode()) 29 | connectionSocket.close() 30 | # 浏览器键入 localhost:***/index.html会有两个请求 31 | # index.html && favicon.ico(网站的图标) -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业1:Web服务器/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspurer/ComputerNetwork/400ee895746e34687094e0a4cb28b5c0b21e7f94/《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业1:Web服务器/__init__.py -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业1:Web服务器/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | inspurer 6 | 7 |
8 | Welcome to inspurer's website 9 |
10 | Click me 11 | 12 | 13 | -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业1:Web服务器/response.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspurer/ComputerNetwork/400ee895746e34687094e0a4cb28b5c0b21e7f94/《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业1:Web服务器/response.html -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业1:Web服务器/test.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | serverSocket = socket(AF_INET, SOCK_STREAM) 3 | serverSocket.bind(("127.0.0.1",9999)) 4 | serverSocket.listen(1) 5 | while True: 6 | print(6) 7 | connectionSocket, addr = serverSocket.accept() 8 | print(8) 9 | try: 10 | print(10) 11 | data = connectionSocket.recv(1024) 12 | print(12) 13 | print(data) 14 | filename = data.split()[1] #filename = /HelloWorld.html 15 | print(15) 16 | f = open(filename[1:]) #f = HelloWorld.html 17 | outputdata = f.read() 18 | print(18) 19 | header = 'HTTP/1.1 200 OK\r\n\r\n' 20 | connectionSocket.send(header.encode()) 21 | print(21) 22 | for i in range(0, len(outputdata)): 23 | connectionSocket.send(outputdata[i].encode()) 24 | connectionSocket.close() 25 | print(25) 26 | except IOError: 27 | print("error") 28 | header = 'HTTP/1.1 404 NOT FOUND\r\n\r\n' 29 | connectionSocket.send(header.encode()) 30 | connectionSocket.close() 31 | #serverSocket.close() 32 | # 这份代码的缺陷在于,当在浏览器输入 localhost:10000/index.html 并回车后, 33 | # 就会建立起一条链接,然后服务器在套接字读数据, 34 | # 由于链接是keep:alive的,如果不出错误这条链接一直会存在 35 | # 服务器端的while循环一直尝试从套接字接口读数据, 36 | # 然而当请求处理完后,再从缓冲区读数据就会使len(data)==0, 37 | # 从而出现IO异常,serverSocket.close(),pycharm出错:OSError: [WinError 10038] 在一个非套接字上尝试了一个操作。 38 | # 事实上浏览器还默认请求的了网站的图标 favicon.ico,把最后一行代码去掉才会出现上述的情况 39 | 40 | -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业2:UDP ping程序/UDPPingClient.py: -------------------------------------------------------------------------------- 1 | import time 2 | from socket import * 3 | serverName = '127.0.0.1' # 主机 4 | serverPort = 12000 5 | # 创建Socket时,AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6 6 | # SOCK_DGRAM指定了这个Socket的类型是UDP 7 | # SOCK_STREAM指定使用面向流的TCP协议 8 | clientSocket = socket(AF_INET, SOCK_DGRAM) 9 | clientSocket.settimeout(1) # 设置超时时间为1s 10 | for i in range(0, 10): 11 | oldTime = time.time() 12 | sendTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(oldTime)) 13 | # encode()把str转成bytes,传输格式要求 14 | message = ('package %d,client_local_time:%s' % (i + 1, sendTime)).encode() 15 | try: 16 | # 发送数据 17 | clientSocket.sendto(message, (serverName, serverPort)) 18 | # 1024指定要接收的最大数据量为1kb = 1024 bytes 19 | # recvfrom是一个系统调用,由用户态转向系统态,从套接口上接收数据,并捕获数据发送源的地址。 20 | # 如果数据报大于缓冲区,那么缓冲区中只有数据报的前面部分,其他的数据都丢失了,并且recvfrom()函数返回WSAEMSGSIZE错误 21 | # 如果没有数据待读,那么除非是非阻塞模式,不然的话套接口将一直等待数据的到来,果没有在Timeout = 1s内接收到数据,此时将返回SOCKET_ERROR错误,错误代码是WSAEWOULDBLOCK。用select()或WSAAsynSelect()可以获知何时数据到达 22 | # UDP的 recvfrom() 和 TCP 的recv()不一样,具体可以看 TCP Ping项目 23 | modifiedMessage, serverAddress = clientSocket.recvfrom(1024) 24 | # 计算往返时间 25 | rtt = time.time() - oldTime 26 | # decode 把bytes转成str 27 | modifiedMessage = modifiedMessage.decode("utf-8") 28 | print('报文 %d 收到来自 %s 的应答: %s,往返时延(RTT) = %fs' % (i+1, serverName,modifiedMessage, rtt)) 29 | except Exception as e: 30 | print('报文 %d: 的请求超时' % (i+1)) # 处理异常 31 | -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业2:UDP ping程序/UDPPingServer.py: -------------------------------------------------------------------------------- 1 | import random 2 | from socket import * 3 | #AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6 4 | #SOCK_DGRAM指定了这个Socket的类型是UDP 5 | serverSocket = socket(AF_INET, SOCK_DGRAM) 6 | #用0.0.0.0绑定到所有的网络地址,还可以用127.0.0.1绑定到本机地址 7 | serverSocket.bind(('127.0.0.1',12000)) 8 | 9 | while True: 10 | #产生一个0到10之间的随机数 11 | rand = random.randint(0, 10) 12 | #从套接口上读取数据,参数为缓冲区大小 13 | message, address = serverSocket.recvfrom(1024) 14 | #通过打印我们可以看到UDP客户端socket的端口是不确定,系统随机分配的 15 | print("收到来自 %s 的报文: (%s)" % (address,message)) 16 | # 把接收到的信息全部转为大写 17 | print("随机数是: %d" % rand) 18 | message = message.upper() 19 | #如果随机数小于4,服务端无应答,客户端就会超时 20 | if rand < 4: 21 | continue 22 | serverSocket.sendto(message, address) 23 | 24 | #参考链接: 25 | # https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432004977916a212e2168e21449981ad65cd16e71201000 26 | 27 | #https://blog.csdn.net/rebelqsp/article/details/22109925 -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业2:UDP ping程序/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspurer/ComputerNetwork/400ee895746e34687094e0a4cb28b5c0b21e7f94/《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业2:UDP ping程序/__init__.py -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业3:邮件客户/SmtpDemo.py: -------------------------------------------------------------------------------- 1 | #作业3:邮件客户 2 | from smtplib import SMTP 3 | from email.mime.text import MIMEText 4 | from email.header import Header 5 | 6 | mail_server = 'smtp.163.com' 7 | #根据发送方邮箱确定邮箱服务器 8 | #qq邮箱的服务器为smtp.qq.com;163邮箱为smtp.163.com 9 | def get_mail_server(sender): 10 | key = sender[sender.index('@')+1:] 11 | return "smtp."+key 12 | 13 | port = '25' ## SMTP协议默认端口是25 14 | sender = '2391527690@qq.com' 15 | mail_server = get_mail_server(sender) 16 | sender_pass = 'put your 授权码 here' #注意是授权码,而不是登录密码,需要在邮箱端先获取 17 | receiver = 'csu_xiaotao@163.com' 18 | mail_msg = 'this is a demo' 19 | 20 | #第一个参数就是邮件正文, 21 | # 第二个参数是MIME的subtype,传入'plain'表示纯文本,最终的MIME就是'text/plain', 22 | # 最后一定要用utf-8编码保证多语言兼容性。 23 | msg = MIMEText(mail_msg, 'plain', 'utf-8') 24 | msg['From'] = sender 25 | msg['To'] = receiver 26 | #Header对象编码文本,包含utf-8编码信息和Base64编码。 27 | msg['Subject'] = Header('来自inspurer的个人计算机', 'utf-8') 28 | try: 29 | server = SMTP(mail_server, port) 30 | #用set_debuglevel(1),可以打印出和SMTP服务器交互的所有信息 31 | #server.set_debuglevel(1) 32 | server.login(sender, sender_pass) 33 | #由于可以一次发给多个人,所以传入一个list,邮件正文是一个str,as_string()把MIMEText对象变成str 34 | server.sendmail(sender, (receiver), msg.as_string() ) 35 | server.quit() 36 | print("邮件发送成功!") 37 | except: 38 | server.quit() 39 | print("邮件发送失败!") 40 | 41 | #更多扩展参见:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432005226355aadb8d4b2f3f42f6b1d6f2c5bd8d5263000#0 42 | -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业3:邮件客户/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspurer/ComputerNetwork/400ee895746e34687094e0a4cb28b5c0b21e7f94/《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/作业3:邮件客户/__init__.py -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/扩展1:TCP ping程序/TCPPingClient.py: -------------------------------------------------------------------------------- 1 | import time 2 | from socket import * 3 | serverName = '127.0.0.1' # 主机 4 | serverPort = 12000 5 | # 创建Socket时,AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6 6 | # SOCK_DGRAM指定了这个Socket的类型是UDP 7 | # SOCK_STREAM指定使用面向流的TCP协议 8 | clientSocket = socket(AF_INET, SOCK_STREAM) 9 | clientSocket.connect((serverName,serverPort)) 10 | clientSocket.settimeout(1) # 设置超时时间为1s 11 | for i in range(0, 10): 12 | oldTime = time.time() 13 | sendTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(oldTime)) 14 | # encode()把str转成bytes 15 | message = ('package %d,client_local_time:%s' % (i + 1, sendTime)).encode() 16 | try: 17 | # 发送数据 18 | clientSocket.send(message) 19 | # UDP的 recvfrom() 和 TCP 的recv()不一样,具体可以看 TCP Ping项目 20 | modifiedMessage = clientSocket.recv(1024) 21 | # 计算往返时间 22 | rtt = time.time() - oldTime 23 | # decode 把bytes转成str 24 | modifiedMessage = modifiedMessage.decode("utf-8") 25 | print('报文 %d 收到来自 %s 的应答: %s,往返时延(RTT) = %fs' % (i+1, serverName,modifiedMessage, rtt)) 26 | except Exception as e: 27 | print('报文 %d: 的请求超时' % (i+1)) # 处理异常 28 | 29 | -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/扩展1:TCP ping程序/TCPPingServer.py: -------------------------------------------------------------------------------- 1 | import random 2 | from socket import * 3 | #AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6 4 | #SOCK_DGRAM指定了这个Socket的类型是UDP 5 | serverSocket = socket(AF_INET, SOCK_STREAM) 6 | #用0.0.0.0绑定到所有的网络地址,还可以用127.0.0.1绑定到本机地址 7 | serverSocket.bind(('127.0.0.1',12000)) 8 | 9 | #最多连接一个客户端 10 | serverSocket.listen(1) 11 | # Tcp server需要两个套接字,比UDP Server多了一个用来连接的套接字 12 | connectionSocket, address = serverSocket.accept() 13 | 14 | while True: 15 | #产生一个0到10之间的随机数 16 | rand = random.randint(0, 10) 17 | 18 | 19 | #从已连接的套接口上读取数据,参数为缓冲区大小 20 | message= connectionSocket.recv(1024) 21 | # TCP的recv()和UDP的recvfrom()的一个区别是recv()读不到数据会立即返回null,不报错 22 | # 还有就是如果数据报大于缓冲区,也不会报错,而是会读完 23 | if not message: 24 | break 25 | 26 | print("收到来自 %s 的报文: (%s)" % (address,message)) 27 | # 把接收到的信息全部转为大写 28 | print("随机数是: %d" % rand) 29 | message = message.upper() 30 | #如果随机数小于4,服务端无应答,客户端就会超时 31 | if rand < 4: 32 | continue 33 | connectionSocket.send(message) 34 | 35 | #参考链接: 36 | # https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432004977916a212e2168e21449981ad65cd16e71201000 37 | 38 | #https://blog.csdn.net/rebelqsp/article/details/22109925 -------------------------------------------------------------------------------- /《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/扩展1:TCP ping程序/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspurer/ComputerNetwork/400ee895746e34687094e0a4cb28b5c0b21e7f94/《计算机网络自顶向下方法》课后编程作业题解/第二章(应用层)/扩展1:TCP ping程序/__init__.py -------------------------------------------------------------------------------- /计算机通信网实验/exp01/python版/client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/6 5 | # file_name: client.py 6 | # description: 月小水长,热血未凉 7 | 8 | from socket import * 9 | 10 | from logger import logger 11 | 12 | clientSocket = socket(AF_INET,SOCK_STREAM) 13 | 14 | clientSocket.connect(("10.10.16.154",12001)) 15 | 16 | while True: 17 | # python3 utf-8编码一个中文居然是三个字节,gbk是两个 18 | receiveMessage = clientSocket.recv(1024) 19 | #print(receiveMessage) 20 | if not receiveMessage: 21 | clientSocket.close() 22 | break 23 | receiveMessage = receiveMessage.decode("utf-8") 24 | logger.info("已收到"+receiveMessage) 25 | print(receiveMessage) -------------------------------------------------------------------------------- /计算机通信网实验/exp01/python版/logger.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import logging 4 | 5 | #返回一个logger实例,如果没有指定name,返回root logger。 6 | # 只要name相同,返回的logger实例都是同一个而且只有一个,即name和logger实例是一一对应的。 7 | # 这意味着,无需把logger实例在各个模块中传递。只要知道name,就能得到同一个logger实例。 8 | logger = logging.getLogger('mylogger') 9 | # 设置总日志级别, 也可以给不同的handler设置不同的日志级别 10 | #设置logger的level, level有以下几个级别: 11 | # 级别高低顺序:NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL 12 | # 如果把looger的级别设置为INFO, 那么小于INFO级别的日志都不输出, 大于等于INFO级别的日志都输出  13 | logger.setLevel(logging.DEBUG) 14 | 15 | # 控制台日志和日志文件使用同一个formatter,formatter用于描述日志的格式 16 | formatter = logging.Formatter( 17 | '%(asctime)s - %(filename)s[line:%(lineno)d] - <%(threadName)s %(thread)d>' + 18 | '- - %(levelname)s: %(message)s' 19 | ) 20 | # asctime:日志产生的时间;filename:产生日志的脚本文件名;lineno:该脚本文件哪一行代码产生了日志 21 | # threadName: 当前线程名;thread: 当前进程名;Process进程同thread线程 22 | # levelname: logger的级别;meesage: 具体的日志信息 23 | 24 | 25 | # 创建Handler, 输出日志到控制台和文件 26 | # 日志文件FileHandler 27 | basedir = os.path.abspath('.') #返回脚本所在的绝对路径 28 | log_dir = os.path.join(basedir, 'logs') # 日志文件所在目录,即‘脚本路径/logs' 29 | if not os.path.isdir(log_dir): 30 | os.mkdir(log_dir) 31 | filename = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime(time.time())) + '.log' # 日志文件名,以当前时间命名 32 | file_handler = logging.FileHandler(os.path.join(log_dir, filename)) # 创建日志文件handler 33 | file_handler.setFormatter(formatter) # 设置Formatter 34 | file_handler.setLevel(logging.INFO) # 单独设置日志文件的日志级别 35 | 36 | # 控制台日志StreamHandler 37 | stream_handler = logging.StreamHandler() 38 | stream_handler.setFormatter(formatter) 39 | # stream_handler.setLevel(logging.INFO) # 单独设置控制台日志的日志级别,注释掉则使用总日志级别 40 | 41 | # 将handler添加到logger中 42 | 43 | logger.addHandler(file_handler) 44 | logger.addHandler(stream_handler) 45 | 46 | #如有不懂,参见博客:https://www.jb51.net/article/42626.htm -------------------------------------------------------------------------------- /计算机通信网实验/exp01/python版/server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/6 5 | # file_name: server.py 6 | # description: 月小水长,热血未凉 7 | 8 | from socket import * 9 | from logger import logger 10 | 11 | serverSocket = socket(AF_INET,SOCK_STREAM) 12 | 13 | serverSocket.bind(('10.10.21.222',12000)) 14 | 15 | serverSocket.listen(1) 16 | 17 | while True: 18 | connectionSocket, addr = serverSocket.accept() 19 | print("已与:",addr,"建立连接") 20 | while True: 21 | for i in range(100): 22 | sendMessage = "数字" + str(i+1) 23 | connectionSocket.send(sendMessage.encode("utf-8")) 24 | logger.info('已发送'+sendMessage) 25 | 26 | 27 | connectionSocket.close() 28 | # send()是阻塞的,发送完数据才返回 29 | # https://www.cnblogs.com/wanzaiyimeng/p/4105937.html 30 | # https://bbs.csdn.net/wap/topics/220012702 -------------------------------------------------------------------------------- /计算机通信网实验/exp01/windows c++版/client.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspurer/ComputerNetwork/400ee895746e34687094e0a4cb28b5c0b21e7f94/计算机通信网实验/exp01/windows c++版/client.cpp -------------------------------------------------------------------------------- /计算机通信网实验/exp01/windows c++版/readme.md: -------------------------------------------------------------------------------- 1 | # 关于windows c++版的几点说明 2 | ## ip地址要改成自己的上网ip 3 | 4 | ## windows c++版下socket和linux下socket编程类似,只不过一些系统调用函数名不一样,如需在linux下运行,自行debug -------------------------------------------------------------------------------- /计算机通信网实验/exp01/windows c++版/server.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inspurer/ComputerNetwork/400ee895746e34687094e0a4cb28b5c0b21e7f94/计算机通信网实验/exp01/windows c++版/server.cpp -------------------------------------------------------------------------------- /计算机通信网实验/exp02/client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/8 5 | # file_name: client.py 6 | # description: 月小水长,热血未凉 7 | 8 | from socket import * 9 | from util import setFCS,fragmentChecker 10 | from constant import segmentFlag,segmentUA,segmentSABM,segmentAddr,segmentDISC,dataDemo,i2s 11 | 12 | import json 13 | import time 14 | 15 | def establish(clientSocket,fragmentCounter): 16 | while True: 17 | sendData = setFCS(dataDemo) 18 | 19 | clientSocket.send(json.dumps(sendData).encode("utf-8")) 20 | # sleep的原因是让确保服务端按照一帧一帧的格式来接收数据 21 | time.sleep(1) 22 | try: 23 | receivedData = clientSocket.recv(1024) 24 | receivedData = receivedData.decode("utf-8") 25 | receivedData = json.loads(receivedData) 26 | if not fragmentChecker(receivedData): 27 | continue 28 | if segmentUA in receivedData.values(): 29 | fragmentCounter = 0 30 | print("已收到UA帧") 31 | print("链接已建立...\n") 32 | break 33 | except: 34 | pass 35 | 36 | def getSendData(): 37 | data = [] 38 | for i in range(8): 39 | data.append({ 40 | "Fs": segmentFlag, # Flag_start 41 | "A": segmentAddr, 42 | "C": "0"+i2s.get(str(i))+"1"+i2s.get(str(fragmentCounter)), 43 | "I": "这是第"+str(i)+"帧", 44 | "FCS": "00000000", 45 | "Fe": segmentFlag # Flag_end 46 | }) 47 | data[i] = setFCS(data[i]) 48 | return data 49 | 50 | 51 | 52 | def infoSender(clientSocket,fragmentCounter): 53 | # 开始发送数据帧,采用停等协议 54 | sendData = getSendData() 55 | endFlag = False 56 | for i, item in enumerate(sendData): 57 | sendDataItem = json.dumps(item).encode("utf-8") 58 | clientSocket.send(sendDataItem) 59 | print("发送了数据帧"+str(i)) 60 | time.sleep(1) 61 | 62 | while True: 63 | try: 64 | receivedData = clientSocket.recv(1024) 65 | receivedData = receivedData.decode("utf-8") 66 | receivedData = json.loads(receivedData) 67 | if not fragmentChecker(receivedData): 68 | print("从接收端接收到的确认帧验证失败") 69 | continue 70 | 71 | C = receivedData.get('C') 72 | #如果是 RR(接收好)帧 73 | if C.startswith("1000"): 74 | #接收状态计数器加一 75 | fragmentCounter += 1 76 | if fragmentCounter is 8: # fragment == i + 1 77 | endFlag = True 78 | break 79 | sendData[i+1]["C"] = "0"+i2s.get(str(i+1))+"1"+i2s.get(str(fragmentCounter)) 80 | sendData[i+1] = setFCS(sendData[i+1]) 81 | break 82 | 83 | if C.startswith("1100"): 84 | endFlag = True 85 | break 86 | except: 87 | pass 88 | 89 | if endFlag: 90 | break 91 | 92 | 93 | if __name__ == "__main__": 94 | clientSocket = socket() 95 | clientSocket.connect(("127.0.0.1", 9920)) 96 | fragmentCounter = 0 97 | 98 | establish(clientSocket,fragmentCounter) 99 | infoSender(clientSocket,fragmentCounter) -------------------------------------------------------------------------------- /计算机通信网实验/exp02/constant.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/8 5 | # file_name: constant.py 6 | # description: 月小水长,热血未凉 7 | 8 | # 标志字段,标识一个帧的开始和结束 9 | segmentFlag = "01111110" 10 | 11 | # 地址字段,全“0”地址为无站地址,这种地址不分配给任何站,仅作作测试 12 | segmentAddr = "00000000" 13 | 14 | # SABM:建立, 15 | segmentSABM = "11110100" 16 | 17 | # DISC:拆除 18 | segmentDISC = "11000110" 19 | 20 | # 对建立和拆除和确认 21 | segmentUA = "11001110" 22 | 23 | dataDemo = { 24 | "Fs":segmentFlag, # Flag_start 25 | "A":segmentAddr, 26 | "C":segmentSABM, 27 | "I":"0000000011111111", 28 | "FCS":"00000000", 29 | "Fe":segmentFlag # Flag_end 30 | } 31 | 32 | # 内存换速度 33 | i2s = { 34 | "0": "000", 35 | "1": "001", 36 | "2": "010", 37 | "3": "011", 38 | "4": "100", 39 | "5": "101", 40 | "6": "110", 41 | "7": "111" 42 | } -------------------------------------------------------------------------------- /计算机通信网实验/exp02/fortest/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/8 5 | # file_name: __init__.py 6 | # description: 月小水长,热血未凉 7 | 8 | import json 9 | b = bytes("1101",encoding="utf-8") 10 | #返回该字节对应的数,int类型,48 11 | print(b[2]) 12 | a = b.decode("utf-8") 13 | # 0 14 | print(a[2]) 15 | #https://segmentfault.com/q/1010000009395651/ 16 | print(b[2*4:3*4]) 17 | 18 | c = json.dumps("111") 19 | print(type(c),c) 20 | 21 | d = "00000000" 22 | e = d.encode("utf-8") 23 | print(len(e),e) 24 | -------------------------------------------------------------------------------- /计算机通信网实验/exp02/fortest/t2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/8 5 | # file_name: t2 6 | # description: 月小水长,热血未凉 7 | 8 | test = "12345" 9 | for i in test: 10 | print(i) 11 | 12 | b = list(test) 13 | print(type(b),type(test)) -------------------------------------------------------------------------------- /计算机通信网实验/exp02/fortest/t3.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/9 5 | # file_name: t3.py 6 | # description: 月小水长,热血未凉 7 | 8 | a = "肖涛" 9 | 10 | b = bytes(a,encoding="utf-8") 11 | 12 | print(b,type(b)) 13 | 14 | c = "肖" 15 | 16 | d = ord("9") 17 | 18 | print(d,type(d)) 19 | 20 | e = bin(d) 21 | 22 | print(e,type(e),len(e)) 23 | 24 | #综上,汉字转换成二进制 25 | a='好' 26 | print(format(ord(a),'b')) #101100101111101,或者 27 | #101100101111101 28 | print(bin(ord(a)),type(ord(a))) #0b101100101111101,转换成八进制和十六进制类似 29 | #0b101100101111101 30 | 31 | #打印汉字表 32 | 33 | # for ch in range(0x4e00,0x9fa6): 34 | # print(chr(ch)) 35 | 36 | #其实只要知道汉字是从0x4e00到0x9fa6就已经足够了。 37 | 38 | print(str(0x4e00)) 39 | print(str(0x9fa6)) 40 | -------------------------------------------------------------------------------- /计算机通信网实验/exp02/fortest/test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/8 5 | # file_name: test.py 6 | # description: 月小水长,热血未凉 7 | 8 | a = "1000" 9 | 10 | b = "0011" 11 | 12 | 13 | d = bytes("这是第0001帧",encoding="utf-8") 14 | 15 | print(len(d),d) 16 | 17 | e = { 18 | 'f':1 19 | } 20 | f = e 21 | 22 | f['f'] = 2 23 | 24 | print(e['f'],f['f']) -------------------------------------------------------------------------------- /计算机通信网实验/exp02/server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/8 5 | # file_name: server.py 6 | # description: 月小水长,热血未凉 7 | 8 | from socket import * 9 | from threading import Thread 10 | from util import fragmentChecker,setFCS 11 | from constant import segmentFlag,segmentUA,segmentSABM,segmentAddr,i2s 12 | import json 13 | import time 14 | 15 | 16 | # 为简化HDLC协议,所有的帧结构的控制字段(也就是C字节)的P/F位全部置为1 17 | # 规定信息字段为16位 18 | 19 | fragmentCounter = 0 20 | def socketHander(connectionSocket,addr): 21 | global fragmentCounter 22 | print("已收到{}的请求".format(addr)) 23 | 24 | #链路建立阶段 25 | while True: 26 | # recv是非阻塞的 27 | receivedData = connectionSocket.recv(1024) 28 | if not receivedData: 29 | print("等待是长情的告白...") 30 | time.sleep(1) 31 | continue 32 | receivedData = receivedData.decode("utf-8") 33 | print("建链之前:",receivedData) 34 | receivedData = json.loads(receivedData) 35 | #如果帧校验不通过,该帧将会被丢失,但是不选择重传,链接建立之后再重传 36 | if not fragmentChecker(receivedData): 37 | continue 38 | 39 | #如果收到SABM,建立链路 40 | if segmentSABM in receivedData.values(): 41 | print("已收到平衡方式帧SABM...\n") 42 | print("链接已建好...\n") 43 | data = { 44 | "Fs": segmentFlag, 45 | "A": segmentAddr, 46 | "C": segmentUA, 47 | "I": "0000000011111111", 48 | "FCS": "00000000", 49 | "Fe": segmentFlag 50 | } 51 | data = setFCS(data) 52 | connectionSocket.send(json.dumps(data).encode("utf-8")) 53 | fragmentCounter = -1 54 | break 55 | 56 | #进入收发数据的循环 57 | while True: 58 | receivedData = connectionSocket.recv(1024) 59 | if not receivedData: 60 | print("等待是长情的告白...") 61 | break 62 | receivedData = receivedData.decode("utf-8") 63 | print("建链之后:", receivedData) 64 | receivedData = json.loads(receivedData) 65 | 66 | # 如果帧校验不通过,该帧将会被丢失,选择重传 67 | if not fragmentChecker(receivedData): 68 | print("To do: 发REJ帧") 69 | #在这里发REJ帧 70 | continue 71 | 72 | C = receivedData.get("C") 73 | 74 | #如果是 DISC 75 | if C.startswith("1100") and C.endswith("010"): 76 | #先发送UA 77 | print("已收到帧DISC...\n") 78 | print("链接已建好...\n") 79 | data = { 80 | "Fs": segmentFlag, 81 | "A": segmentAddr, 82 | "C": segmentUA, 83 | "I": "0000000011111111", 84 | "FCS": "00000000", 85 | "Fe": segmentFlag 86 | } 87 | data = setFCS(data) 88 | connectionSocket.send(json.dumps(data).encode("utf-8")) 89 | break 90 | #再关闭 91 | pass 92 | 93 | else: 94 | # 计数状态器加一 95 | fragmentCounter += 1 96 | data = { 97 | "Fs": segmentFlag, 98 | "A": segmentAddr, 99 | "C": "10001"+i2s.get(str(fragmentCounter)), 100 | "I": "0000000011111111", 101 | "FCS": "00000000", 102 | "Fe": segmentFlag 103 | } 104 | data = setFCS(data) 105 | 106 | 107 | connectionSocket.send(json.dumps(data).encode("utf-8")) 108 | print("接收到数据:",receivedData.get("I")) 109 | 110 | if fragmentCounter is 7: 111 | break 112 | 113 | 114 | 115 | if __name__ == "__main__": 116 | serverSocket = socket(AF_INET, SOCK_STREAM) 117 | 118 | serverSocket.bind(("127.0.0.1", 9920)) 119 | 120 | #listen()将服务器的连接由主动转成被动 121 | serverSocket.listen(5) 122 | 123 | while True: 124 | connectionSocket, addr = serverSocket.accept() 125 | # 多线程处理并发 126 | Thread(target=socketHander,args=(connectionSocket,addr)).start() 127 | -------------------------------------------------------------------------------- /计算机通信网实验/exp02/util.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # author: inpurer(月小水长) 3 | # pc_type lenovo 4 | # create_date: 2018/12/8 5 | # file_name: util 6 | # description: 月小水长,热血未凉 7 | 8 | #发送端FCS检验 9 | def setFCS(data): 10 | fcs = ['0','0','0','0','0','0','0','0'] 11 | #信息字段的格式为"0000000011111111"或者"这是第i帧" 12 | hanzi = data.get("I") 13 | if len(hanzi)>5: 14 | pass 15 | else: 16 | for ch in hanzi: 17 | # 字符转编码值 19968~40870 18 | ch = ord(ch) 19 | # 如果是0~9,为了统一起来,不做处理 20 | if ch<57: 21 | continue 22 | else: 23 | #汉字的范围:0x4e00~0x9fa6 19968~40870 24 | ch = str(ch) 25 | ch = "000" + ch #00019968 26 | ch = list(ch) 27 | for i, item in enumerate(ch): 28 | if item > '4': 29 | fcs[i] = '1' 30 | else: 31 | fcs[i] = '0' 32 | for key in data.keys(): 33 | if key == "FCS" or key == "I": 34 | continue 35 | value = data.get(key) 36 | valued = list(value) 37 | for i,item in enumerate(valued): 38 | if item is fcs[i]: 39 | fcs[i] = '0' 40 | else: 41 | fcs[i] = '1' 42 | for j,item in enumerate(fcs): 43 | if item is '0': 44 | fcs[j] = '1' 45 | else: 46 | fcs[j] = '0' 47 | fcs = "".join(fcs) 48 | data['FCS'] = fcs 49 | return data 50 | 51 | 52 | # 接收端FCS检验,算法和生成FCS类似 53 | def fragmentChecker(receivedData): 54 | #return True 55 | fcsChecker = receivedData.get("FCS") 56 | #没有帧校验位,立即返回 57 | if not fcsChecker: 58 | return False 59 | 60 | fcs = ['0','0','0','0','0','0','0','0'] 61 | #信息字段的格式为"0000000011111111"或者"这是第i帧" 62 | hanzi = receivedData.get("I") 63 | if len(hanzi)>5: 64 | pass 65 | else: 66 | for ch in hanzi: 67 | # 字符转编码值 19968~40870 68 | ch = ord(ch) 69 | # 如果是0~9,为了统一起来,不做处理 70 | if ch<57: 71 | continue 72 | else: 73 | #汉字的范围:0x4e00~0x9fa6 19968~40870 74 | ch = str(ch) 75 | ch = "000" + ch #00019968 76 | ch = list(ch) 77 | for i, item in enumerate(ch): 78 | if item > '4': 79 | fcs[i] = '1' 80 | else: 81 | fcs[i] = '0' 82 | for key in receivedData.keys(): 83 | #python3 不能用 is 来判断两个字符串是否相等 84 | if key == "FCS" or key == "I": 85 | continue 86 | value = receivedData.get(key) 87 | valued = list(value) 88 | for i,item in enumerate(valued): 89 | if item is fcs[i]: 90 | fcs[i] = '0' 91 | else: 92 | fcs[i] = '1' 93 | for j,item in enumerate(fcs): 94 | if item is '0': 95 | fcs[j] = '1' 96 | else: 97 | fcs[j] = '0' 98 | fcs = "".join(fcs) 99 | print(receivedData,fcs) 100 | if fcsChecker == fcs: 101 | return True 102 | else: 103 | return False 104 | pass 105 | 106 | 107 | --------------------------------------------------------------------------------