在 C# 中使用 C 套接字时出现问题

Issue when Using c sockets in c#

我正在尝试使用 c# 中的系统套接字创建套接字。

我编写了以下代码:

using System;
using System.Net;
using System.Runtime.InteropServices;

namespace test_socket

{
    public class Program
    {
        [DllImport("libc", EntryPoint = "socket", SetLastError = true)]
    public static extern int socket(int domain, int type, int protocol);
    //public static extern int socket(AddressFamily domain, SocketType type, ProtocolFamily protocol);

    [DllImport("libc", EntryPoint = "close", SetLastError = true)]
    public static extern int close(int handle);

    [DllImport("libc", EntryPoint = "connect", SetLastError = true)]
    public static extern int connect(int socket, sockaddr_in addr, int socklen_t);
    [StructLayout(LayoutKind.Sequential)]
    public struct sockaddr_in
    {
        public byte sin_len;
        public byte sin_family;
        public ushort sin_port;
        public uint sin_addr;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] sin_zero;
    };
        public static void Main() {
            Console.WriteLine("Hello World");
            int msock = socket(2, 1, 0); //AF_INET, SOCK_STREAM, 0
            IPAddress ipa = IPAddress.Parse("127.0.0.1");
            int sock_struct_size = Marshal.SizeOf(typeof(sockaddr_in));
            sockaddr_in sin = new sockaddr_in()
            {
                sin_len = (byte)sock_struct_size,
                sin_family = 2, //2
                sin_port = (ushort)IPAddress.HostToNetworkOrder((short)4569),
#pragma warning disable 618
                sin_addr = (uint)ipa.Address,
#pragma warning restore 618
                sin_zero = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }
            };


            var test_sock = connect(msock, sin, sock_struct_size);

            Console.WriteLine(test_sock);
            Console.WriteLine(Marshal.GetLastWin32Error());
        }
}
}

我在尝试连接我的套接字时总是收到 -1。 我当然可以在本地连接到端口 4569:

远程登录 127.0.0.1 4569

正在尝试 127.0.0.1... 连接到 localhost.

我不知道我错过了什么。

如果测试上述代码,请将端口 4569 替换为打开的端口,例如 22 (ssh)。

使用 dotnetcore 3.1 和 mac os 10.15.3

进行测试

我制作了一个示例 C++ 项目来测试套接字,它工作正常:

// Client side C/C++ program to demonstrate Socket programming 
#include <stdio.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <string.h> 
#define PORT 4569 
   
int main(int argc, char const *argv[]) 
{ 
    int sock = 0, valread; 
    struct sockaddr_in serv_addr; 
    char *hello = "Hello from client"; 
    char buffer[1024] = {0}; 
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
        printf("\n Socket creation error \n"); 
        return -1; 
    } 
    printf("sizeof: %lu", sizeof(serv_addr));

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(PORT); 

     printf("port: %hu", serv_addr.sin_port);
       
    // Convert IPv4 and IPv6 addresses from text to binary form 
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)  
    { 
        printf("\nInvalid address/ Address not supported \n"); 
        return -1; 
    } 

    uint x = serv_addr.sin_addr.s_addr;
   
    printf("addr: %du", x);
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) 
    { 
        printf("\nConnection Failed \n"); 
        return -1; 
    } 
    send(sock , hello , strlen(hello) , 0 ); 
    printf("Hello message sent\n"); 
    valread = read( sock , buffer, 1024); 
    printf("%s\n",buffer ); 
    return 0; 
} 

我检查了 port/ip 的 struct size 和 int 值,它们也匹配

@bmigette 找到了答案,但是在对这个问题悬赏之后,他没有足够的声誉 post 自己:

"[...] 结果是您需要在套接字函数之后立即调用 GetLastWin32Error [...] 请在此处为感兴趣的人找到答案:pastebin.com/raw/j6w8HLgp"

以防将来 link 不可用,最终解决方案中的工作主要功能如下:

public unsafe static void Main() {
    Console.WriteLine(" World");
    int msock = socket(AF_INET, SOCK_STREAM, 0);
    IPAddress ipa = IPAddress.Parse("127.0.0.1");
    int sock_struct_size = Marshal.SizeOf(typeof(sockaddr_in));
    in_addr ina = new in_addr();
    var adbytes = ipa.GetAddressBytes();
    ina.s_addr[0] = adbytes[0];
    ina.s_addr[1] = adbytes[1];
    ina.s_addr[2] = adbytes[2];
    ina.s_addr[3] = adbytes[3];


    sockaddr_in sin = new sockaddr_in()
    {
        sin_family = 2, //2
        sin_port = (ushort)IPAddress.HostToNetworkOrder((short)4569),

    };
    sin.sin_addr = ina; //.s_addr = (ushort)ipa.Address;

    Console.WriteLine(Marshal.SizeOf(sin));

    var test_sock =connect(msock, (sockaddr*)&sin, sock_struct_size);
    var errno = Marshal.GetLastWin32Error();
    Console.WriteLine(test_sock);
    Console.WriteLine(errno);

}

也可以找到必要的结构定义 here and here