2009-10-01 2 views
6

Ho un indirizzo IP in tipo char Come char ip = "192.123.34.134" Voglio incrementare l'ultimo valore (134). Qualcuno come dovrei farlo? Penso che dovrei convertirlo in un numero intero e poi tornare indietro, ma sfortunatamente non so come? :(sto usando C++.Come si incrementa un indirizzo IP rappresentato come una stringa?

Please help me!

Grazie, Kampi

+4

Vuoi dire char * ip, giusto? –

risposta

23

È possibile convertire l'indirizzo IP da una stringa in un intero utilizzando inet_addr, poi, dopo la manipolazione di esso, riconvertirlo in una stringa con inet_ntoa.

Vedere the documentation per queste funzioni per ulteriori informazioni su come utilizzarle.

Ecco una piccola funzione che farà ciò che si vuole:

// NOTE: only works for IPv4. Check out inet_pton/inet_ntop for IPv6 support. 
char* increment_address(const char* address_string) 
{ 
    // convert the input IP address to an integer 
    in_addr_t address = inet_addr(address_string); 

    // add one to the value (making sure to get the correct byte orders) 
    address = ntohl(address); 
    address += 1; 
    address = htonl(address); 

    // pack the address into the struct inet_ntoa expects 
    struct in_addr address_struct; 
    address_struct.s_addr = address; 

    // convert back to a string 
    return inet_ntoa(address_struct); 
} 

Includere <arpa/inet.h> su sistemi * nix, o <winsock2.h> su Windows.

+0

So che il mio sarà un'esecuzione più veloce, ma questa risposta è decisamente più corretta. – Erich

+0

Suppongo che tu intenda inet_ntop invece che * deprecato * inet_ntoa, giusto? ** Esatto? ** – Powerlord

+0

@R. Bemrose IPv6 complica inutilmente questa domanda; la domanda originale affermava che l'indirizzo sarebbe in formato quad punteggiato che implica solo IPv4. Aggiornerò volentieri il codice se avete suggerimenti per sostituire le chiamate htonl/ntohl con qualcosa che funzioni per gli indirizzi IPv6. –

2

vorrei scrivere un metodo che accetta una stringa in quel formato.
convertirlo in 4 numeri interi. Incremento. (test di ricezione importante)
Poi riconvertire in una stringa.

Se vuoi somthing più a lungo termine e robusto di una classe che rappresenta l'indirizzo IP. Poi si mantiene la classe di manipolare come oppotuno e convertire in stringa quando necessario.

#include <iostream> 
#include <istream> 
#include <sstream> 
#include <string> 
#include <stdexcept> 



class MyIp 
{ 
    struct Dot 
    {}; 
    struct Byte 
    { 
     Byte(unsigned char& val) 
      :m_val(val) 
     {} 
     unsigned char& m_val; 
    }; 
    friend std::istream& operator>>(std::istream& str,MyIp::Dot const& d); 
    friend std::istream& operator>>(std::istream& str,MyIp::Byte const& b); 
    friend std::ostream& operator<<(std::ostream& str,MyIp const& ip); 
    public: 
     MyIp(std::string const& ip) 
     { 
      std::stringstream str(ip); 
      str >> Byte(ad[0]) >> Dot() >> Byte(ad[1]) >> Dot() >> Byte(ad[2]) >> Dot() >> Byte(ad[3]); 
      std::string leftover; 
      if (str >> leftover) 
      { throw std::runtime_error("InvalidIP: Long"); 
      } 
     } 
     void inc(int index) 
     { 
      if ((index >= 0) && (index <=3)) 
      { 
       ++ad[index]; 
       if (ad[index] == 0) 
       { 
        inc(index-1); 
       } 
      } 
     } 
    private: 
     unsigned char ad[4]; 
}; 
std::istream& operator>>(std::istream& str,MyIp::Dot const& d) 
{ 
    char x = str.get(); 
    if (x != '.') 
    { throw std::runtime_error("Invalid IP: Dot"); 
    } 
    return str; 
} 
std::istream& operator>>(std::istream& str,MyIp::Byte const& b) 
{ 
    unsigned int val; 
    str >> val; 
    if (!str || val > 255) 
    { throw std::runtime_error("Invalid IP: Val"); 
    } 
    b.m_val = static_cast<unsigned char>(val); 
    return str; 
} 
std::ostream& operator<<(std::ostream& str,MyIp const& ip) 
{ 
    return str << static_cast<unsigned int>(ip.ad[0]) 
       << "." << static_cast<unsigned int>(ip.ad[1]) 
       << "." << static_cast<unsigned int>(ip.ad[2]) 
       << "." << static_cast<unsigned int>(ip.ad[3]); 
} 

int main() 
{ 
    try 
    { 
     std::string ip("127.0.0.1"); 

     MyIp addr(ip); 

     std::cout << addr << "\n"; 
     addr.inc(3); 
     std::cout << addr << "\n"; 
    } 
    catch(std::exception const& e) 
    { 
     std::cout << "What: " << e.what() << "\n"; 
    } 
} 
+0

questo è divertente. +1. – glomad

+0

Alla gente piace uccidere :-) –

-2

Questo sito ha mangiato le mie schede, quindi ci riproverò. Sono sicuro che c'è una libreria per fare qualcosa di simile, ma dovrebbe funzionare (supponendo che la mia sintassi non sia incasinata) abbastanza da far passare l'idea.

pseudo codice:

char[] ipAddress= "192.123.34.134"; 

if (ipAddress[ipAddress.Length-1] == '9') 
{ 
    if(ipAddress[ipAddress.Length-2]=='9') 
    { 
     ipAddress[ipAddress.Length-1]='0'; 
     ipAddress[ipAddress.Length-2]='0'; 
     ipAddress[ipAddress.Length-3]=(char)ipAddress[ipAddress.Length-3]+1; 
    } 
    else 
    { 
     ipAddress[ipAddress.Length-2]=(char)ipAddress[ipAddress.Length-2]+1; 
     ipAddress[ipAddress.Length-1]='0'; 
    } 
} 
else 
{ 
    ipAddress[ipAddress.Length-1]=(char)ipAddress[ipAddress.Length-1]+1; 
} 
+0

Che dire di '192.123.34.255'? –

+0

A questo punto, ho pensato che quel tipo di controllo dell'intervallo era già stato gestito. Per me, non penso che avrebbe senso trasformare 192.123.34.255 in 192.123.35.0, che penso che le altre soluzioni passerebbero attraverso un intero. – Erich

+0

Eh, ora che lo dici, x.x.x.99 o x.x.x.9 non funziona neanche. Potrei sistemarli, ma in realtà le risposte sopra riportate usando le funzioni della libreria socket sono più corrette. – Erich

4

rapida/Dirty!

void increment(std::string& ip) 
{ 
    std::string::size_type dot = ip.find_last_of('.'); 
    std::stringstream stream(ip.substr(dot+1)); 
    int part = 0; 

    stream >> part; 

    part++; 

    stream.str(""); stream.clear(); 

    stream << part; 

    ip.replace(dot+1, std::string::npos, stream.str()); 
} 
+0

Stavo scrivendo mentre stavi scrivendo il codice :) Le mie abilità in C++ sono arrugginite ma il tuo aspetto è perfetto. Bello spettacolo. – Deverill

0

È inoltre possibile utilizzare la posizione dell'ultimo "." e prendi da lì fino alla fine per convertire in un int, aumentalo 1, controlla i limiti e poi convertilo in una stringa e aggiungilo alla parte di base.

0

Questo probabilmente non è molto sano, ma è stato divertente pensarci.

Poiché lo spazio dell'indirizzo IP è di 32 bit, è possibile scrivere una funzione per convertire gli indirizzi IP in numeri interi a 32 bit senza segno. Quindi puoi aggiungere o sottrarre 1 o quanto vuoi e riconvertire in un indirizzo IP. Non dovresti preoccuparti del controllo del range.

In pseduo-codice per 192.123.34.134 faresti:

int i = (192 << 24) + (123 << 16) + (34 << 8) + 134 

Più in generale, per a.b.c.D:

int i = (a << 24) + (b << 16) + (c << 8) + d 

Ora cambiano i tanto quanto si vuole (i++, i+=10000) e riconvertire:

String ip = (i >> 24) + "." + 
      ((i >> 16) mod 256) + "." + 
      ((i >> 8) mod 256) + "." + 
      (i mod 256); 

Excuse la sintassi - non ho potuto scrivere C++ per salvare me stesso.

MK

+3

Questo è esattamente ciò che inet_addr_t è, come nella risposta di Neil, quindi non è necessario eseguire il rollover. Quindi, che sia ragionevole o meno, è quello che i programmatori C hanno fatto per anni ... –

+0

Immagino di essere stato in un mondo Java troppo a lungo se penso che il bit-twiddling sia un po 'troppo hardcore, grazie per il puntatore ! (Il gioco di parole non è stato originariamente previsto ma tenuto quando viene individuato). – monorailkitty

3
int a,b,c,d; 
sscanf(str, "%d.%d.%d.%d", &a,&b,&c,&d); 
sprintf(str, "%d.%d.%d.%d\0", a,b,c,d+1);