关于CentOS和Windows之间端口号的不同行为

时间:2014-02-27 04:58:47

标签: c sockets winsock recvfrom

我已经制作了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);
}

2 个答案:

答案 0 :(得分: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()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;
}

答案 1 :(得分:-1)

 return s.sin_port;

那应该是

return ntohs(s.sin_port);

它在CentOS中有效可能是因为'ntohs(i)== i'在那里。