0

我已经制作了 C 程序,它们是服务器和客户端。他们使用 udp 互相发送消息。

服务器一直等到客户端发送消息。

当我从客户端控制台键入一些消息时,客户端会将消息发送到服务器。

服务器从客户端接收消息,然后服务器将在其控制台上回显该消息并将相同的消息发送回客户端。

最后,客户端在其控制台上显示服务器发回消息的消息。

在此过程中,客户端在其控制台上显示其源端口号。服务器还显示发送消息的客户端的源端口号recvfrom ()

奇怪的是,如果我在 windows7 上运行它们,客户端和服务器之间的源端口号是不同的,但如果我在 CentOS6.4 上运行它们,源端口号是相同的。

有谁知道这是怎么回事?

我的代码如下。

[服务器]

#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <sys/types.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <string.h>
int charToInt(char myText[]) {
     char s[] = {'1', '2', '3', '4'};
     const int n = strlen(myText);
     int i, m = 0;

    for(i = 0; i < n; ++ i){
             m = m * 10 + myText[i] - '0';
    }
        printf("%d\n", m);
    return m;
 }
int
main(int argc,char *argv[])
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);

    int sock;
 struct sockaddr_in addr;
 struct sockaddr_in from;

 int sockaddr_in_size = sizeof(struct sockaddr_in);

 char buf[2048];
 char comnd[2048];
 char *bye="bye";

 printf("#############  udpServer start prot number is %d\n",charToInt(argv[1]));
 sock = socket(AF_INET, SOCK_DGRAM, 0);
 addr.sin_family = AF_INET;
 addr.sin_port = htons(charToInt(argv[1]));

 addr.sin_addr.s_addr = INADDR_ANY;
 bind(sock, (struct sockaddr *)&addr, sizeof(addr));

 while (!strncmp(buf,bye,3)==0){
        memset(buf, 0, sizeof(buf));
    recvfrom(sock, buf, sizeof(buf), 0,(struct sockaddr *)&from, &sockaddr_in_size);

    printf("recived '%s'(%d) from %s:%d\n", buf, strlen(buf),
                              inet_ntoa(from.sin_addr),ntohs(from.sin_port));

         sendto(sock, buf, sizeof(buf), 0, (struct sockaddr *)&from, sizeof(from));

        printf("send back %s to %s:%d\n", buf,inet_ntoa(from.sin_addr),ntohs(from.sin_port));
    printf("\n");
  } 
  printf("bye now");
  close(sock);
  return 0;
}

[客户]

 #define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <sys/types.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <string.h>
#include <errno.h>
int charToInt(char myText[]) {
     char s[] = {'1', '2', '3', '4'};
     const int n = strlen(myText);
     int i, m = 0;

    for(i = 0; i < n; ++ i){
             m = m * 10 + myText[i] - '0';
    }
        printf("%d\n", m);
    return m;
 }

 int getMyPortNum(int sock)
{
    struct sockaddr_in s;
    socklen_t sz = sizeof(s);
    getsockname(sock, (struct sockaddr *)&s, &sz);
    return s.sin_port;
}

int
main(int agrc,char *argv[])
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);

    char *host;
    int port;
    int sock;
 struct sockaddr_in dst_addr = {0};
 struct sockaddr_in src_addr = {0};
 struct sockaddr_in rcv_addr = {0};

 int sockaddr_in_size = sizeof(struct sockaddr_in);
 int defPortNum;


 char message[2048];
 char comnd[2048];
 int i;
 int ret;
 int connect_ret;
 int bind_ret;
 char *p;
 char buf[2048];

 host=argv[1];
 port=charToInt(argv[2]);

 printf("host = %s\n",host);
 printf("port = %d\n",port);
 sock = socket(AF_INET, SOCK_DGRAM, 0);

 dst_addr.sin_family = AF_INET;
 dst_addr.sin_addr.s_addr = inet_addr(host);
 dst_addr.sin_port = htons(port);

 printf("getMyPortNum before bind() is %d\n",ntohs(src_addr.sin_port));

 bind_ret = 0;

 bind_ret = bind(sock,(struct sockaddr *)&src_addr,sizeof(src_addr));
    src_addr.sin_port = getMyPortNum(sock);

 printf("Default Client port is %d\n",ntohs(src_addr.sin_port));
 if(bind_ret>=0){
    printf("bind() error ret = %d:%s\n",bind_ret,strerror(errno));
    perror("bind()");
    return bind_ret;
 } 

 memset(message, 0, sizeof(message));
 memset(comnd, 0, sizeof(comnd));
 memset(buf,0,sizeof(buf));

 while(!strncmp(comnd,"bye",3)==0){
    if(strncmp(message,"bye",3)==0){
        strcpy(comnd,message);
    }else{
            printf("typ your message (exit:stop Client bye:stop server)>>>\t"); 
        fgets(comnd,sizeof(comnd),stdin);
        comnd[strlen(comnd) - 1] = '\0'; 
        strcpy(message,comnd);
    }
    ret = sendto(sock, message, strlen(message), 0,
             (struct sockaddr *)&dst_addr, sizeof(dst_addr));
    printf("Server port (dst port) for sending is %d\n",ntohs(dst_addr.sin_port));
    if(ret<0){
        printf("Send Error ret = %d:%s\n",ret,strerror(errno));
        return ret;
    }else{
        printf("Waiting for sendBack !!!\n");
        printf("Client port for recieving  is %s:%d\n"
                ,inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port));
        ret = recvfrom(sock, buf, sizeof(buf), 
                0,(struct sockaddr *)&rcv_addr, &sockaddr_in_size); 
        if(ret<0){
            printf("ReciveError ret = %d\n",ret);
        }else{
            printf("Sentback %s from %s:%d\n"
                    ,buf,inet_ntoa(rcv_addr.sin_addr)
                    ,ntohs(rcv_addr.sin_port));
        }
    }
 }
 close(sock);
}
4

2 回答 2

1

每次调用时都可能使用新的随机源端口sendto(),除非您明确地bind()将客户端套接字连接到特定源端口(并且不依赖操作系统bind()为您执行隐式操作)。这是客户端可以显示其自己的源端口的唯一可靠方式,因为sendto()不报告实际使用的源端口。请记住,与 TCP 不同,UDP 是无连接的,因此源端口不需要保持一致,除非您强制使用它。

更新:您的客户端代码有一行记录网络字节顺序端口号,而它应该记录主机字节顺序端口号:

//printf("getMyPortNum before bind() is %d\n",myName.sin_port);
printf("getMyPortNum before bind() is %d\n",port);

除此之外,你为什么要创建自己的charToInt()函数,而不是使用标准函数,比如atoi()or strtol()

你也没有做很好的错误处理。

尝试更多类似的东西:

[服务器]

#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <sys/types.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

int printerror2(char func[], int errnum)
{
    printf("%s error = %d:%s\n", func, errnum, strerror(errnum));
    perror(func);
    return errnum;
}

int printerror(char func[])
{
    return printerror2(func, errno);
}

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    int ret = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (ret != 0)
        return printerror2("WSAStartup()", ret);

    int sock;
    in_port_t port;
    struct sockaddr_in addr;
    struct sockaddr_in from;
    int from_size;

    char buf[2048];

    port = atoi(argv[1]);
    printf("############# udpServer port number is %hu\n", port);

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == -1)
        return printerror("socket()");

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
    if (ret == -1)
        return printerror("bind()");

    do
    {
        from_size = sizeof(from);

        ret = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&from, &from_size);
        if (ret == -1)
            return printerror("recvfrom()");

        printf("received '%*s'(%d) from %s:%hu\n",
            ret, buf, ret, inet_ntoa(from.sin_addr), ntohs(from.sin_port));

        ret = sendto(sock, buf, ret, 0, (struct sockaddr *)&from, from_size);
        if (ret == -1)
            return printerror("sendto()");

        printf("sent back '%*s'(%d) to %s:%hu\n",
            ret, buf, ret, inet_ntoa(from.sin_addr), ntohs(from.sin_port));
        printf("\n");
    } 
    while ((ret != 3) || (strncmp(buf, "bye", 3) != 0));

    printf("bye now");

    close(sock);
    return 0;
}

[客户]

#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <sys/types.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

int printerror2(char func[], int errnum)
{
    printf("%s error = %d:%s\n", func, errnum, strerror(errnum));
    perror(func);
    return errnum;
}

int printerror(char func[])
{
    return printerror2(func, errno);
}

int getMyPortNum(int sock, in_port_t *port)
{
    struct sockaddr_in s;
    socklen_t sz = sizeof(s);
    int ret = getsockname(sock, (struct sockaddr *)&s, &sz);
    if (ret == 0)
       *port = s.sin_port;
    return ret;
}

int main(int agrc, char *argv[])
{
    WSADATA wsaData;
    int ret = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (ret != 0)
        return printerror2("WSAStartup", ret);

    char *host;
    in_port_t port;
    int sock;
    struct sockaddr_in dst_addr;
    struct sockaddr_in src_addr;
    struct sockaddr_in from_addr;
    int from_size;

    char buf[2048];

    host = argv[1];
    port = atoi(argv[2]);

    printf("host = %s\n", host);
    printf("port = %hu\n", port);

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == -1)
        return printerror("socket()");

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.sin_family = AF_INET;
    src_addr.sin_addr.s_addr = INADDR_ANY;
    src_addr.sin_port = 0;

    ret = bind(sock, (struct sockaddr *)&src_addr, sizeof(src_addr));
    if (ret == -1)
        return printerror("bind()");

    ret = getMyPortNum(sock, &(src_addr.sin_port));
    if (ret == -1)
        return printerror("getsockname()");

    printf("Client port is %hu\n", ntohs(src_addr.sin_port));

    memset(&dst_addr, 0, sizeof(dst_addr));
    dst_addr.sin_family = AF_INET;
    dst_addr.sin_addr.s_addr = inet_addr(host);
    dst_addr.sin_port = htons(port);

    do
    {
        printf("type your message (exit: stop Client, bye: stop server)>>>\t"); 
        fgets(buf, sizeof(buf), stdin);

        if (strcmp(buf, "exit") == 0)
            break;

        ret = sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr));
        if (ret == -1)
            return printerror("sendto()");

        printf("Waiting for send back !!!\n");

        from_size = sizeof(from_addr);

        ret = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&from_size, &from_size); 
        if (ret == -1)
            return printerror("recvfrom()");

        printf("Received '%*s' from %s:%hu\n",
            ret, buf, inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port));
    }
    while ((ret != 3) || (strncmp(buf, "bye", 3) != 0));

    close(sock);
    return 0;
}
于 2014-02-27T06:20:04.193 回答
-1
 return s.sin_port;

那应该是

return ntohs(s.sin_port);

它在 CentOS 中工作大概是因为那里有 'ntohs(i) == i'。

于 2014-02-27T09:37:25.040 回答