【问题标题】:tcp server not binding to specific porttcp 服务器未绑定到特定端口
【发布时间】:2017-09-19 09:05:21
【问题描述】:

问题是无论我设置什么端口,服务器都会连接到另一个端口。 例如,在我的代码中,我设置了端口 20000(但我也尝试了其他数字),但是当我打印端口号时它完全不同(现在它显示 8270) 这条线正确吗? indirizzo_serv.sin_port=htons(20000);

另一个问题是服务器不接受多个命令,我的意思是当我发送“时间”并得到答案时,我不能发送任何其他命令。服务器代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<time.h> //per data e ora
#include<locale.h> //per la traduzione di giorno e mese


int main(void)
{
char buf[100]={0},tmp[10]={0};
time_t t; //tempo "grezzo" (rawtime)
struct tm *info; //struttra che contiene le informazioni su data e ora
struct sockaddr_in indirizzo_serv;
int fd1,fd2;
socklen_t len;

setlocale(LC_ALL,"it_IT.utf8"); //per stampare giorno e mese in italiano, ricavato dando da terminale locale -a

indirizzo_serv.sin_family=AF_INET;
indirizzo_serv.sin_port=htons(20000);
indirizzo_serv.sin_addr.s_addr=htonl(INADDR_ANY);
fd1=socket(PF_INET,SOCK_STREAM,0); //socket tcp di rete
bind(fd1,(struct sockaddr*)&indirizzo_serv,sizeof(indirizzo_serv));
listen(fd1,5);

sprintf(tmp,"Numero porta= %d\n",indirizzo_serv.sin_port);
write(STDOUT_FILENO,tmp,strlen(tmp));
bzero(tmp,10);

fd2=accept(fd1,NULL,NULL);

sleep(2);

while(1){
    read(fd2,buf,100);
    if((strcmp(buf,"TIME\n"))==0){
        time(&t);
        info=localtime(&t);
        strftime(buf,100,"Sono le ore %H.%M%n",info);
        write(fd2,buf,strlen(buf));
        bzero(buf,100);
    }
    else if((strcmp(buf,"DATE\n"))==0){
        time(&t);
        info=localtime(&t);
        strftime(buf,100,"Oggi è %A, %e %B %G %n",info);
        write(fd2,buf,strlen(buf));
        bzero(buf,100);
    }
    else if((strcmp(buf,"PORT\n"))==0){
        indirizzo_serv.sin_port=htons(0); //porta casuale
        len=sizeof(indirizzo_serv);
        getsockname(fd1,(struct sockaddr*)&indirizzo_serv,&len);
        sprintf(tmp,"Numero porta= %d\n",indirizzo_serv.sin_port);
        write(STDOUT_FILENO,tmp,strlen(tmp));
        write(fd2,tmp,strlen(tmp)); //invio la porta al client sotto forma di stringa
        bzero(tmp,10);
    }
}

close(fd1);
return 0;
}

客户端代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<ctype.h> //per toupper

int main(void)
{
struct sockaddr_in indirizzo;
int fd,i=0,nport;
char buf[100]={0};

indirizzo.sin_family=AF_INET;
inet_aton("127.0.0.1",&indirizzo.sin_addr);
indirizzo.sin_port=htons(10000);

fd=socket(PF_INET,SOCK_STREAM,0);

connect(fd,(struct sockaddr*)&indirizzo,sizeof(indirizzo));

while(1){
    write(STDOUT_FILENO,"Scrivi il comando da inviare al server tra i seguenti: TIME, DATE, PORT.\n",strlen("Scrivi il comando da inviare al server tra i seguenti: TIME, DATE, PORT.\n"));
    read(STDIN_FILENO,buf,sizeof(buf));
    while(buf[i]){
        buf[i]=toupper(buf[i]);
        i++;
    }
    if((strcmp(buf,"PORT\n"))==0){
            bzero(buf,100);
            read(fd,buf,sizeof(buf));
            nport=atoi(buf);
            indirizzo.sin_port=htons(nport);
            connect(fd,(struct sockaddr*)&indirizzo,sizeof(indirizzo));

    }
    write(fd,buf,strlen(buf)); //incio comando al server
    bzero(buf,100);
    read(fd,buf,100); //leggo il messaggio ricevuto dal server
    write(STDOUT_FILENO,buf,strlen(buf)); //stampo a video il messaggio
    bzero(buf,100);
}

close(fd);
return 0;

}

【问题讨论】:

    标签: c sockets unix tcp


    【解决方案1】:

    sprintf(tmp,"Numero porta= %d\n",indirizzo_serv.sin_port);
    

    您创建一个包含端口的网络字节顺序值的字符串。您需要使用ntohs 获取主机字节顺序:

    sprintf(tmp,"Numero porta= %d\n",ntohs(indirizzo_serv.sin_port));
    

    网络字节顺序为big endian,而基于现代x86(或x86_64)的PC 为little endian。这是您问题的最可能原因。

    htonsshort 值从主机字节顺序转换为网络字节顺序,ntohs 则相反。

    【讨论】:

      【解决方案2】:

      这是因为您以 Network 格式打印端口号。您的机器肯定是 little-endian,这意味着表示数字的字节与网络顺序相反。

      由于您指定了20000,因此在网络排序中,这表示为0x4E20(十六进制),但您的机器从右到左读取它,因此读取0x204E,即8270

      然后使用ntohs() 将其转换回来。

      【讨论】:

        【解决方案3】:

        可能没有严格涉及这种情况,但是在服务器代码中您声明了 tmp[10],后来您 sprintf 超过 10 个字节,还覆盖了 *info 和 indirizzo_serv。

        【讨论】:

          猜你喜欢
          • 2018-12-04
          • 2018-03-15
          • 2023-03-04
          • 2012-08-17
          • 2020-12-28
          • 1970-01-01
          • 2013-05-19
          • 2012-02-02
          • 1970-01-01
          相关资源
          最近更新 更多