Δικτυακός Προγραμματισμός σε C (Sockets..etc) + Απορίες

...ασύγχρονα μαθήματα γλώσσας C

Δικτυακός Προγραμματισμός σε C (Sockets..etc) + Απορίες

Δημοσίευσηαπό Star_Light » 19 Ιουν 2011, 21:48

Ανοιγώ αυτο το θρεντ για τον δικτυακό προγραμματισμό για όποιον ή όποιους ασχολούνται να έχουμε και εδω τις απορίες μας ομαδοποιημένες και να μην μπλεχτούν με άλλα θέματα. Λοιπον προσπαθώ να φτιάξω ενα απλό socket σε C ( τα 2 πρωτα στάδια βασικά τις κλήσεις connect() & bind() γιατι στην C τα πραγματα ειναι πιο ζορικα απο οτι στην PHP) :D

Θα δώσω ένα σχήμα θεωρίας για αυτούς που ξεκινάνε τωρα και θα παρατεθεί και ο κώδικας πιο κατω ο οποιος μπορει να τρέξει μεν αλλα παλι τα ιδια και εδω οπως με την php δεν μπορω να δω αν τελικα μου κανει bind ή οχι κάποια port :problem:

ΘΕΩΡΙΑ - ΕΙΣΑΓΩΓΗ ΣΤΟΝ ΔΙΚΤΥΑΚΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟ

Καταρχην τι είναι ενα socket?

Socket είναι το ένα άκρο μιας full duplex επικοινωνίας μεταξύ 2 προγραμμάτων που εκτελούνται δηλαδη μιας επικοινωνίας στην οποία μπορώ και να στείλω αλλα και να λάβω ταυτόχρονα. Κάθε πρόγραμμα διαβάζει απο και γράφει σε ενα socket με τρόπο παρόμοιο με της εγγραφής και ανάγνωσης σε ενα filesystem . Στα αρχεία του filesystem μας παίζει ένας δείκτης τύπου FILE* ο οποιος απλα αναφέρει ένα αρχείο δίσκου. Με τον ιδιο τρόπο και για να χειριστούμε ενα socket θα πρεπει να ορίσουμε εναν socket descriptor (στον δικο μου κωδικα θα φαίνεται σαν sd σε άλλους ειναι και σαν socket_desc).

Μια βασική διαφορά στον προγραμματισμό στα sockets μεταξυ C & php έγκειται στις δομές. Η php οπως μου επισήμανε και ο ΑΠοστολης στο θρέντ αποριών της php δεν χρειάζεται να κάνει διαχείριση χαμηλού επιπέδου απλα στην C τα πραγματα ειναι πιο "βαθειά".

Η δομή sockaddr_in (για την οικογένεια πρωτοκολλων IPv4) για να αποθηκεύσει διευθύνσεις και γενικά παρέχουν πληροφορίες στις συναρτήσεις του socket API . Με 2 λογια δηλαδη

μπορεί καποιος να τα διαβασει καλυτερα απο τον Beej's Guide.

Ενας TCP server ξεκινάει με τις ακόλουθες κλήσεις :

socket() -> bind () -> listen() -> accept() /* ΑΠο το σημείο αυτο και μετα γίνεται το TCP 3-way handshake με τον client στην φάση connect() */

και στην συνέχεια υπάρχουν και άλλες κλήσεις οπως η read () , write() και τέλος η close() αυτα για το socket του TCP server

ο client θα έχει τις κλήσεις socket() -> connect() -> write() -> read() και τελος close() (τα βελη δεν εχουν καμια σχεση με δεικτες εδω απλα δειχνουν την ροη) .

Τα παραπανω ειναι απλα συναρτήσεις που υλοποιούν τις αντίστοιχες κλήσεις συστήματος για να καταστεί δυνατή η επικοινωνια και η ανταλλαγη δεδομενων αναμεσα σε εναν server και εναν client συναρτήσεις που περιγράφονται απο το API της C για τα sockets.

socket() -> δημιουργία και αρχικοποίηση ενος socket

επιστρέφει εναν ακέραιο ανάλογο με τις ρουτίνες διαχείρισης αρχείων.

Η συνάρτηση που το υλοποίει στην C είναι ->

Κώδικας: Επιλογή όλων
int socket(int family,int type, int protocol)

δηλαδη συμφωνα και με τα παραπάνω
Κώδικας: Επιλογή όλων
int sd;
sd=socket(AF_INET,SOCKSTREAM,0);
/*AF_INET για πρωτοκολλα ιντερνετ
SOCK_STREAM ΓΙΑ TCP συνδεσεις
Η τιμη 0 ειναι η τιμη που θα επιστραφει κατα την επιτυχη εκτελεση */


Η συνάρτηση bind() απλά δεσμεύει το sd που έχει επιστρέψει η κλήση socket() με μια τοπικη διεύθυνση και μια θυρα "λεγοντας" στο συστημα οτι τα μηνύματα που έρχονται στα συγκεκριμένα port-interface απευθύνονται στην συγκεκριμένη διαδικασία.

Η κλήση listen() ειναι προαιρετική. H συνάρτηση αυτη θα δέχεται εισερχόμενες συνδέσεις στην socket του συστήματος που ήδη έχει δεσμευτεί απο την bind μολις γίνει μια επιτυχής σύνδεση ένας νέος περιγραφέας υποδοχής επιστρέφεται και μπορει να χρησιμοποιηθεί για την επικοινωνία του προγράμματος.

Η connect() απλα αρχικοποιεί τα TCP sockets με το handshaking .
H κλήση accept() κάνει ουσιαστικα αποδοχή μιας αίτησης σύνδεσης που περιμένει στην ουρά του sd. Αν η ουρά είναι άδεια η διεργασία μπλοκάρει (εδω ουσιαστικα εννοει μιας και οσοι έχουν διαβάσει για τους servers θα έχουν διαβάσει και για τις διεργασίες δαίμονες που περιμένουν στο παρασκήνιο κάποια αίτηση απο καποιον client για να την επεξεργαστούν και μέχρι τοτε απλα βρίσκονται στο παρασκήνιο καπως ετσι ειναι και εδω) μεχρι να εμφανιστεί κάποια αίτηση μολις γίνει η αποδοχή επιστρέφονται πληροφορίες για τον client (port,IP) και ενας νέος descriptor new_sd που αποτελεί πλεον το ακρο ενος καινουργιου καναλιού.

Οι κλήσεις read()-write() κάνουν οτι λεει και το ονομα τους αναγνωση και εγγραφη δηλαδη και τελος η συνάρτηση close() κλείνει το socket που έχει δημιουργηθεί με την αντίστοιχη κλήση. Ακολουθεί κώδικας για connect() & bind().
Τελευταία επεξεργασία από Star_Light και 20 Ιουν 2011, 03:23, έχει επεξεργασθεί 2 φορά/ες συνολικά
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Απορίες στον Δικτυακό Προγραμματισμό σε C (Sockets..etc)

Δημοσίευσηαπό Star_Light » 19 Ιουν 2011, 22:05

Κώδικας: Επιλογή όλων
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<stdlib.h>

struct sockadrr_in
{
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
}; /*ORISMOS Tis domis gia ta function API tis C opws i bind */
typedef struct sockaddr_in sin; /*Orismos sunwnimou */

int main(void)
{
int sd;
int rc;

sd=socket(AF_INET,SOCK_STREAM,0); /*Dimiourgia socket */

if(sd==-1)
{
perror("Fail to create"); /* An o sd dn dwsei mia egkuri timi dilwse errno me tin perror() */
exit(EXIT_FAILURE);
}

sin info =
{
"AF_INET",
htons(8834),
inet_addr("192.168.1.9")

}; /* Prospa8eia arxikopoihshs */
rc=bind(sd,(struct sockaddr *)&info,sizeof(info));
if(rc==-1)
printf("error");
sleep(10);
close(sd);
}


Μου βγάζει βεβαια αρκετά errors ο κώδικας τρέχει κανονικά και δουλεύει και η sleep() για 10 δευτερόλεπτα
αλλα και παλι οταν παω να ανοιξω το Telnet στην πορτα 8834 και με την IP που εχω εδω δεν μου το τρεχει....
δεν μου εμφανίζει δηλαδη το μήνυμα Trying .... για 10 δευτερολεπτα οπως κάνει σε άλλες συνδέσεις και μετα να μου
δωσει μια connection refused μιας και δεν εχω ρυθμίσει κάποια άλλη κλήση συστήματος ακομη απο τον κωδικα μου

ειδα και αποειδα και εβαλα και μια if(rc==-1) για να δω αν τελικα η bind δουλευει καλα
και οντως μου εμφανιζει error . Μπορει κάποιος να υποθέσει πως η δομή που έχω δημιουργήσει
δεν έχει αρχικοποιηθεί σωστα τελοςπαντων. Εχω και 2ο κώδικα ο οποιος κανει καλά την αρχικοποιήση και δεν βγάζει τόσα warnings οπως ο 1ος
αλλα και παλι οταν παω να τρεξω απο το τερματικο παλι στο Telnet δεν μου εμφανίζει αυτα που πρεπει οταν κτυπαω στην αντιστοιχη IP και Port

o 2oς κωδικας :

Κώδικας: Επιλογή όλων

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main()
{
int socket_desc;
struct sockaddr_in address;
int rc;

/* dimiourgia socket */
socket_desc=socket(AF_INET,SOCK_STREAM,0);

/* Gia na anafer8ei to sfalma sto errno mesw tis perror*/
if (socket_desc==0)
{
perror("Create socket");
exit(EXIT_FAILURE);
}

/* arxikopoihsh domis*/
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
/* host to network for short tipo dedomenwn me tin htons */
address.sin_port = htons(7000);
/* bind stin 7000 */
bind(socket_desc,(struct sockaddr *)&address,sizeof(address));

if(rc==1)
printf("error");

sleep(10);

/* kleisimo */
close(socket_desc);
}


τα ιδια παθαινα και στην PHP δεν μπορουσε να μου δεσμευσει πορτες. Ξερει τελικα κανεις ποιο ειναι το προβλημα?????

Π.Σ Ο 2ος κωδικας δεν ειναι δικος μου http://shoe.bocks.com/net/files/ απλα του εχω βαλει τα δικα μου σχολια.
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Απορίες στον Δικτυακό Προγραμματισμό σε C (Sockets..etc)

Δημοσίευσηαπό Star_Light » 19 Ιουν 2011, 22:42

Δηλαδη για να γινω πιο κατανοητος η εξοδος απο το telnet ειναι

Κώδικας: Επιλογή όλων
kostas@kostas-SSL:~$ telnet 192.168.1.9 8834
Trying 192.168.1.9...
Connected to 192.168.1.95.
Escape character is '^]'.




Ενω εγώ περιμενα να ειναι κατι σε αυτο

Κώδικας: Επιλογή όλων
kostas@kostas-SSL:~$ telnet 192.168.1.9 8834
Trying 192.168.1.9...
telnet: Unable to connect to remote host: Connection refused


μετα απο 10 δευτερολεπτα δηλαδη να μου εβγαζε αυτο το μηνυμα... Μιας και εχω φτασει μεχρι και την bind οποτε απλα το ανοιγει το αρχικοποιει το δεσμευει και τελος μετα κλεισιμο..... Αυτο δεν γινεται ουτε με τους 2 κωδικες ας πουμε..... :/
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση


Επιστροφή στο Μαθήματα C