The release is Tencent tlinux3, the kernel is Linux 5.4, it's modified by 
Tencent.

---

In golang, net.ListenTCP will set REUSEADDR to quickly reuse the same 
ipport, but listen twice shouldn't success unless REUSEPORT set.

When the problem occurs, we try use `fuser port/tcp` to check if there's 
only one process listening on the same ipport. Yes, there's only one.
The other process trying to listen on the same ipport succeeded:
```
ln, err := net.ListenTCP(...), 
```
here err is nil. 

Then:
```
conn, err := ln.Accept()
```
here conn is nil, and err != nil, but in our previous code, the err is 
ignored (bad practice), I didn't know what error it returned.
And I cannot reproduce this problem.
On Tuesday, November 18, 2025 at 8:38:59 PM UTC+8 Robert Engels wrote:

> 
> I believe that if the port has pre ious connections still in the 
> CLOSE_WAIT state (could be a previous run of the same app) the port cannot 
> be opened.
>
> Linux also has a  REUSE_PORT option that allows multiple processes to bind 
> to the same port and it balances the incoming requests automatically. 
>
> On Nov 18, 2025, at 3:36 AM, 'Brian Candler' via golang-nuts <
> [email protected]> wrote:
>
> When the problem occurs, I suggest you look at "ss -natp" ("netstat 
> -natp" on older systems) and see if you really do have two listening 
> sockets on the same port and address.
>
>
> If you do, that seems like a kernel bug / some sort of race.  What kernel 
> version is the VM running?  (The kernel on the physical host shouldn't 
> really make any difference).
>
> On Tuesday, 18 November 2025 at 03:11:24 UTC Zhang Jie (Kn) wrote:
>
>> Hello everyone,
>>
>> Over the past year, I've encountered two strange issues 
>> with net.ListenTCPand listener.Accept. Without explicitly 
>> enabling reuseport, multiple service processes on the same machine, all 
>> searching for available ports starting from 9000, managed to successfully 
>> call listenon the same IP and port. At least when calling net.ListenTCP, it 
>> returned err == nil, and the error only appeared during listener.Accept. 
>> However, at the time, we weren't explicitly checking the returned error or 
>> printing the error message. Instead, when we found the returned conn == 
>> nil, we kept retrying listener.Acceptin a for-loop.
>>
>> We've reproduced this issue twice within a year. The environment was a 
>> virtual machine allocated on a physical host with a Linux 5.4 kernel, and 
>> it was very difficult to reproduce. Our immediate fix was to add the error 
>> checking logic and print the specific error. While handling this issue, we 
>> also ran into the problem with netError.Temporary().
>>
>> I completely agree with Ian's insight: "Whether an error is temporary 
>> depends on what you were doing at the time." For the specific case 
>> of listener.Accept(), even if netError.Temporary()returns true, retrying 
>> doesn't necessarily mean the service can remain available. Errors always 
>> manifest in wildly different ways. In our specific flawed usage scenario, 
>> the service had already successfully registered with the name service, and 
>> other services had already discovered it and started sending requests. 
>> However, because the listenwasn't actually successful (the IP:port was held 
>> by another process), it resulted in persistent access failures.
>>
>> But if we don't use Temporary(), asking developers to enumerate all 
>> possible temporary errors that can be retried isn't a very straightforward 
>> task. Could several categorical functions, similar to IsTimeout, be 
>> provided to allow developers to combine them freely? For example, something 
>> like if ne.IsTimeout() || ne.IsXXX() || ne.IsYYY().
>>
>> On Friday, April 22, 2022 at 6:39:39 AM UTC+8 Caleb Spare wrote:
>>
>>> On Thu, Apr 21, 2022 at 7:16 AM 'Bryan C. Mills' via golang-nuts 
>>> <[email protected]> wrote: 
>>> > 
>>> > Even ENFILE and EMFILE are not necessarily blindly retriable: if the 
>>> process has run out of files, it may be because they have leaked (for 
>>> example, they may be reachable from deadlocked goroutines). 
>>> > If that is the case, it is arguably better for the program to fail 
>>> with a useful error than to keep retrying without making progress. 
>>> > 
>>> > (I would argue that the retry loop in net/http.Server is a mistake, 
>>> and should be replaced with a user-configurable semaphore limiting the 
>>> number of open connections — thus avoiding the file exhaustion in the first 
>>> place!) 
>>>
>>> ENFILE might be caused by a different process entirely, no? 
>>>
>>> > 
>>> > On Wednesday, April 20, 2022 at 10:49:20 PM UTC-4 Ian Lance Taylor 
>>> wrote: 
>>> >> 
>>> >> On Wed, Apr 20, 2022 at 6:46 PM 'Damien Neil' via golang-nuts 
>>> >> <[email protected]> wrote: 
>>> >> > 
>>> >> > The reason for deprecating Temporary is that the set of "temporary" 
>>> errors was extremely ill-defined. The initial issue for 
>>> https://go.dev/issue/45729 discusses the de facto definition of 
>>> Temporary and the confusion resulting from it. 
>>> >> > 
>>> >> > Perhaps there's a useful definition of temporary or retriable 
>>> errors, perhaps limited in scope to syscall errors such as EINTR and 
>>> EMFILE. I don't know what that definition is, but perhaps we should come up 
>>> with one and add an os.ErrTemporary or some such. I don't think leaving 
>>> net.Error.Temporary undeprecated was the right choice, however; the need 
>>> for a good way to identify transient system errors such as EMFILE doesn't 
>>> mean that it was a good way to do so or could ever be made into one. 
>>> >> 
>>> >> To frame issue 45729 in a different way, whether an error is 
>>> temporary 
>>> >> is not a general characteristic. It depends on the context in which 
>>> >> it appears. For the Accept loop in http.Server.Serve really the only 
>>> >> plausible temporary errors are ENFILE and EMFILE. Perhaps the net 
>>> >> package needs a RetriableAcceptError function. 
>>> >> 
>>> >> Ian 
>>> >> 
>>> >> 
>>> >> 
>>> >> > On Wednesday, April 20, 2022 at 6:02:34 PM UTC-7 [email protected] 
>>> wrote: 
>>> >> >> 
>>> >> >> In Go 1.18 net.Error.Temporary was deprecated (see 
>>> >> >> https://go.dev/issue/45729). However, in trying to remove it from 
>>> my 
>>> >> >> code, I found one way in which Temporary is used for which there 
>>> is no 
>>> >> >> obvious replacement: in a TCP server's Accept loop, when deciding 
>>> >> >> whether to wait and retry an Accept error. 
>>> >> >> 
>>> >> >> You can see an example of this in net/http.Server today: 
>>> >> >> 
>>> https://github.com/golang/go/blob/ab9d31da9e088a271e656120a3d99cd3b1103ab6/src/net/http/server.go#L3047-L3059
>>>  
>>> >> >> 
>>> >> >> In this case, Temporary seems useful, and enumerating the 
>>> OS-specific 
>>> >> >> errors myself doesn't seem like a good idea. 
>>> >> >> 
>>> >> >> Does anyone have a good solution here? It doesn't seem like this 
>>> was 
>>> >> >> adequately considered when making this deprecation decision. 
>>> >> >> 
>>> >> >> Caleb 
>>> >> > 
>>> >> > -- 
>>> >> > You received this message because you are subscribed to the Google 
>>> Groups "golang-nuts" group. 
>>> >> > To unsubscribe from this group and stop receiving emails from it, 
>>> send an email to [email protected]. 
>>> >> > To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/golang-nuts/1024e668-795f-454f-a659-ab5a4bf9517cn%40googlegroups.com.
>>>  
>>>
>>> > 
>>> > -- 
>>> > You received this message because you are subscribed to the Google 
>>> Groups "golang-nuts" group. 
>>> > To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to [email protected]. 
>>> > To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/golang-nuts/1826b3b5-c147-4015-9769-984fd84eacb3n%40googlegroups.com.
>>>  
>>>
>>>
>> -- 
> You received this message because you are subscribed to the Google Groups 
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
>
> To view this discussion visit 
> https://groups.google.com/d/msgid/golang-nuts/86d641cd-4503-4568-b491-f82b5fa705c9n%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/golang-nuts/86d641cd-4503-4568-b491-f82b5fa705c9n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/89d781f5-c876-4b8c-b505-88361c42bbaan%40googlegroups.com.

Reply via email to