【问题标题】:Issue when Using c sockets in c#在 c# 中使用 c 套接字时的问题
【发布时间】:2020-03-13 14:29:30
【问题描述】:

我正在尝试使用 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... 连接到本地主机。

我不知道我错过了什么。

如果测试上述代码,请将端口 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; 
} 

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

【问题讨论】:

  • 你选择互操作有什么原因吗?对我来说似乎是在重新发明轮子。
  • 你为什么不使用托管套接字?有一个 System.Net 程序集,其中包含所有这些好东西供您使用。你可以开始here
  • 嗨,原因是我正在使用需要套接字句柄的外部库:int maapi_connect(int sock, const struct sockaddr* srv, int srv_sz);
  • 可以从托管的Socket 对象中获取本机句柄。也就是说,无法为您的问题提供一个好的答案,因为它缺乏一个好的minimal reproducible example 可以可靠地重现问题。很可能您只是遇到了一些网络配置问题,这对于 Stack Overflow 来说是题外话,但如果是编码错误,您需要提供必要的minimal reproducible example,以便人们可以重现和诊断您的错误。
  • 我可以肯定地说这不是网络问题,因为我已经对此进行了测试并且我是一名网络工程师,但我同意这个可重现的例子。我将在星期一提供一个可用的 c++ 示例和不可用的 c# 示例

标签: c# sockets interop libc


【解决方案1】:

@bmigette 找到了答案,但在悬赏问题后,他没有足够的声望自己发布:

"[...] 原来你需要在套接字函数之后立即调用 GetLastWin32Error [...] 感兴趣的人请在这里找到答案:pastebin.com/raw/j6w8HLgp"

如果将来链接不可用,最终解决方案中的工作主要功能如下:

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);

}

也可以在herehere 中找到必要的结构定义。

【讨论】:

    猜你喜欢
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 2010-11-14
    • 2022-10-06
    • 1970-01-01
    相关资源
    最近更新 更多