golang 解决 socket: too many open files, 以及 too many open files
同事写的一段代,码业务场景:需要多次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的更多相关文章
- C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)
介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...
- 解决Socket粘包问题——C#代码
解决Socket粘包问题——C#代码 前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加 ...
- 切实解决socket连接掉线检测
原文:切实解决socket连接掉线检测 版权声明:欢迎转载,但是请保留出处说明 https://blog.csdn.net/lanwilliam/article/details/51698807 新公 ...
- 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 ...
- 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 ...
- 解决Socket.IO在IE8下触发disconnect时间过长
本文地址: http://www.cnblogs.com/blackmanba/p/solve-socketIO-IE8-emit-disconnect-too-long.html或者http://f ...
- golang 解决 TCP 粘包问题
什么是 TCP 粘包问题以及为什么会产生 TCP 粘包,本文不加讨论.本文使用 golang 的 bufio.Scanner 来实现自定义协议解包. 协议数据包定义 本文模拟一个日志服务器,该服务器接 ...
- 解决 LLVM 错误 cannot specify -o when generating multiple output files
Xcode 9 使用 LLVM 混淆器会提示错误: clang: error: cannot specify -o when generating multiple output files 通过对比 ...
- 解决socket负载均衡集群方案和代码实现
有一段时间,在考虑下socket 之间集群 可以在Nginx 下可以 但是不同服务器之间怎么通讯呢 后来自己也想可不可以用什么东西或者中间件来通讯 ,后来在百度之下 发现果然就是按照我所想的 ,在网上 ...
- 解决socket粘包的两种low版模式 os.popen()和struct模块
os.popen()模式 server端 import socket import os phone = socket.socket() # 实例化一个socket对象 phone.bind((&qu ...
随机推荐
- iOS第三方库汇总(转)
原文:http://mp.weixin.qq.com/s?__biz=MjM5OTM0MzIwMQ==&mid=2652551221&idx=1&sn=617f4d42bc52 ...
- angular 路由守卫Observable异步请求串联
假设路由守卫有这种场景 需要使用observable同时发送多个Http 请求,判断request2返回的数据中是否存在request1返回的数据 使用async await export class ...
- EF中使用SqlBulkCopy
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using S ...
- element ui form 表单 校验upload是否有上传
查到资料 可以绑定在一个多选上,校验此绑定的值 1 <el-form-item label="上传图片" prop="双向绑定值"> 2 <e ...
- Spring @aspect
在 开发过程中,需要对每个 方法 执行时 进行日志 记录, 故而 整理一下, 有关 AOP 的 相关 知识点. 1. 切面类: @Aspect : 定义切面类, 加上 @Aspect,@Compo ...
- Python的入门学习Day 16~18——form”夜曲编程“
Day 16 Day 17 time:2021.8.14. 今天七夕.激动,喜悦.平静呼吸,嘻嘻~ 也许我也是天空.去看课程了,嗯.今天重点学习了循环的对立面--"跳出循环"的 ...
- PyQt5模块说明
pyqt5的类别分为几个模块,包括以下: QtCoreQtGuiQtWidgetsQtMultimediaQtBluetoothQtNetworkQtPositioningEnginioQtWebSo ...
- vue的增删改查(简单版)
<template> <div class="about"> <div> <input type="te ...
- 如何用python脚本采集某网图片
一.前言: 今天学了两个工具urlopen 和etree,这两个小工具至关重要.urllib.request模块提供了最基本的构造HTTP请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时它还 ...
- 晓晓---python文件的读写模式的理解
1. python读取文件模式的自我理解:'r' open for reading (default)----只读模式打开文件,不能写:'w' open for writing, truncating ...