同事写的一段代,码业务场景:需要多次GET请求一个三方服务的http 接口,获取数据后写入文件。发现有部分文件没有写入。查看日志出现了报错“socket: too many open files”、“too many open files”。

在此记录一下解决办法。这也是新写Go的人很常见的问题。

示例代码:

package main

import (
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
) func main() {
requestAndWriteFile()
} // 从接口获取数据并且写入文件
func requestAndWriteFile() {
// 约有5千个元素
params := []string{
"001",
"002",
"003",
"004",
}
hostname := "https://test.com/api"
for _, val := range params {
url := hostname + "?=code" + val
byteData, err := Get(url)
if err != nil{
fmt.Println(err)
continue
}
fileFullPath := "/var/" + val + ".txt"
path := filepath.Dir(fileFullPath)
_, err = os.Stat(path)
// 不存在则创建
if err != nil {
err = os.MkdirAll(path, 0755)
if err != nil {
fmt.Println("创建目录错误", err)
continue
}
}
file, e := os.OpenFile(fileFullPath, os.O_RDWR|os.O_CREATE, 0766)
// 关闭文件
defer file.Close()
if e != nil {
fmt.Println("打开目录错误", e)
}
_, er := file.Write(byteData)
if er != nil {
fmt.Println("写入文件错误", er)
}
} } // 发送GET请求
func Get(url string) ([]byte, error) {
response, err := http.Get(url)
if err != nil {
return nil, err
}
// 关闭响应
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}

上面的代码中使用了“defer response.Body.Close()” 关闭了http响应体,打开的文件也用“defer file.Close()”关闭了。乍一看似乎没有问题。但是Go的HTTP请求本身是有坑的,释放不及时,会造成同时有多个socket连接。第二个问题就是“defer file.Close()” 写在for 循环中,那么按照defer的特性,将在函数requestAndWriteFile return之前执行多个defer,越先出现的defer越后执行。多次循环后打开的文件数就超过了系统限制,就会报错“too many open files”。

解决办法是:对于http请求导致“socket: too many open files”,采用公用的 http.Transport;对于“too many open files”,写入文件的操作,封装成函数,在函数中打开关闭文件,就可以避免。修改后的示例代码:

package main

import (
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
) // 全局 transport
var globalTransport *http.Transport func init() {
globalTransport = &http.Transport{}
} func main() {
requestAndWriteFile()
} func requestAndWriteFile() {
// 约有5千个元素
params := []string{
"001",
"002",
"003",
"004",
}
hostname := "https://test.com/api"
for _, val := range params {
url := hostname + "?=code" + val
byteData, err := Get(url)
if err != nil{
fmt.Println(err)
continue
}
fileFullPath := "/var/" + val + ".txt"
writeFile(fileFullPath, byteData)
} } func writeFile(fileFullPath string, byteData []byte) error {
path := filepath.Dir(fileFullPath)
_, err := os.Stat(path)
// 不存在则创建
if err != nil {
err = os.MkdirAll(path, 0755)
if err != nil {
fmt.Println("创建目录错误")
return err
}
}
file, e := os.OpenFile(fileFullPath, os.O_RDWR|os.O_CREATE, 0766)
// 一定要close
defer file.Close()
if e != nil {
fmt.Println("打开目录错误")
}
_, er := file.Write(byteData)
if er != nil {
fmt.Println("写入文件错误")
return er
} return nil
} // 发送get请求
func Get(uri string) ([]byte, error) {
client := http.Client{
Transport: globalTransport,
}
res, err := client.Get(uri)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
} return body, nil }

如果确实有必要同时打开超过系统限制的多个文件,那么可以使用ulimit 命令修改。

golang 解决 socket: too many open files, 以及 too many open files的更多相关文章

  1. C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)

    介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...

  2. 解决Socket粘包问题——C#代码

    解决Socket粘包问题——C#代码 前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加 ...

  3. 切实解决socket连接掉线检测

    原文:切实解决socket连接掉线检测 版权声明:欢迎转载,但是请保留出处说明 https://blog.csdn.net/lanwilliam/article/details/51698807 新公 ...

  4. 14.7.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量和大小

    14.7.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量和大小 改变 InnoDB ...

  5. 14.5.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量

    14.5.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量 改变InnoDB redo ...

  6. 解决Socket.IO在IE8下触发disconnect时间过长

    本文地址: http://www.cnblogs.com/blackmanba/p/solve-socketIO-IE8-emit-disconnect-too-long.html或者http://f ...

  7. golang 解决 TCP 粘包问题

    什么是 TCP 粘包问题以及为什么会产生 TCP 粘包,本文不加讨论.本文使用 golang 的 bufio.Scanner 来实现自定义协议解包. 协议数据包定义 本文模拟一个日志服务器,该服务器接 ...

  8. 解决 LLVM 错误 cannot specify -o when generating multiple output files

    Xcode 9 使用 LLVM 混淆器会提示错误: clang: error: cannot specify -o when generating multiple output files 通过对比 ...

  9. 解决socket负载均衡集群方案和代码实现

    有一段时间,在考虑下socket 之间集群 可以在Nginx 下可以 但是不同服务器之间怎么通讯呢 后来自己也想可不可以用什么东西或者中间件来通讯 ,后来在百度之下 发现果然就是按照我所想的 ,在网上 ...

  10. 解决socket粘包的两种low版模式 os.popen()和struct模块

    os.popen()模式 server端 import socket import os phone = socket.socket() # 实例化一个socket对象 phone.bind((&qu ...

随机推荐

  1. kafka数据顺序一致

    问题: kafka如何发送顺序消息 方案:kafka可以通过partitionKey,将某类消息写入同一个partition,一个partition只能对应一个消费线程,以保证数据有序. 也就是说生产 ...

  2. wampServer本地php环境配置笔记

    红色的为关键步骤,其余可以不看. 一:安装时 , 报 : 1.应用程序无法正常启动0xc0000007b 清单机确定关闭应用程序 : 2. 缺少XXX.dll文件 解决方法都是: C:\Windows ...

  3. RN 报错信息总结

    我使用的是 VScode 编辑器,有时候,卸载包,安装包就会编译失败,解决方式 gradlew clean 编译错误 Execution failed for task ':app:compileDe ...

  4. Mysql 字符集的设置和修改

    Show variables like 'character%';  //显示目前mysql默认 字符集 显示数据连接字符集 修改字符集 D:\mysql>Net stop mysql   // ...

  5. 路飞前台全局css 全局配置文件,安装axios,安装vue-cookies,安装elementui,安装bootstrap和jq,后台主页模块表设计,后台主页模块轮播图接口,录入数据,跨域问题详解

    目录 路飞前台全局css 全局配置文件,安装axios,安装vue-cookies,安装elementui,安装bootstrap和jq,后台主页模块表设计,后台主页模块轮播图接口,录入数据,跨域问题 ...

  6. 无锡哲讯谈食品行业如何利用SAP信息化方案实现数字化转型?

    随着人们对生活品质的提高,大家对食品安全问题越来越重视.食品企业如果缺乏相应的监管和追溯,很容易陷入困难的被动局面.SAP系统可以对食品加工企业供应链.生产销售.食品质量控制等环节的信息化管控,降低食 ...

  7. win10 安装mariadb

    在MariaDB10.2.17 以前.解压后在目录下看到my-huge.ini.my-innodb-heavy-4G.ini.my-large.ini.my-medium.ini.my-small.i ...

  8. 读后笔记 -- Python 全栈测试开发 Chapter11:Python + Requests 实现接口测试

    11.1 Requests 框架 11.1.1 requests 请求 1. reqeusts 库 安装 pip install requests 2. requests 库 GET 方法,参数通过 ...

  9. ffmpeg 截取视频

    ffmpeg -ss 00:00:03 -t 22 -i output20230301.mp4 output20230301_0.mp4 -ss:开始时间 -t:持续时间 -i:输入 接着是输出

  10. 学习- vue 中 API $attr 用法

    2.4.0新增 定义:包含了父作用域不作为 prop 被识别(且获取)的 attribute 绑定( class 和 style 除外).当一个组件没有声明任何 prop 时,这里会包含所有父作用域的 ...