2012-03-27 2 views
0

для соляриев был запрограммирован следующий c-код. Теперь я должен был портировать его на Ubuntu Linux:Использование C-сокета от Solaris на Ubuntu

UdP клиента

/* Modul fuer Echo-Client mittels UDP 
    Autor K. Felten    Letzte Aenderung: 02.04.2008 
                Anpassung an Solaris 9 
Aufruf mit: udpclient IP-Addr UDP-Port             
------------------------------------------------------------------------------ 
* Example of server using UDP protocol. 
------------------------------------------------------------------------------ 
As with the TCP server example, the Internet address for the bind is specified 
as INADDR_ANY. 
The client program: 
------------------------------------------------------------------------------ 
*/ 
#include "inet.h" 
#include <netdb.h> 
#include <ctype.h> 

int check_dot(address) 
char *address; 
{ int dotcount = 0; 
    for (; *address != '\0'; address++) 
     if (*address == '.') 
     dotcount++; 
     else if (!isdigit(*address)) 
       dotcount = 4; 
    return (dotcount); 
} 

int main(int argc, char *argv[]) 
{ 
    int sockfd; 
    int i, *iaddr; 
    unsigned char *addr; 
    struct sockaddr_in cli_addr, serv_addr; 
    char *server_ip_addr; 
    int dotnum; /* Number of Dots in Address (argv[1] */ 
    unsigned short server_port; /* Serverport-Nr. */ 
    struct hostent *server; 

    if (argc != 3){ 
     printf("2 Arguments required:\n"); 
     printf(" - IP-Address, Dot Notation\n"); 
     printf(" - UDP-Port-Nr.\n"); 
     exit(1); 
    } 
    else server_ip_addr = argv[1]; 
    dotnum = check_dot(server_ip_addr); 
    if (dotnum != 3) 
    { /* Address not in Dot-Notation */ 
     server = gethostbyname(server_ip_addr); 
     if (server != NULL) 
     { iaddr = (int *) *(server->h_addr_list); /* get 4 Byte Internet-addr. */ 
     /* Testausgaben */ 
     printf("Server-Name  =%s\n", server->h_name); 
     printf("Server-Addr_length=%d\n", server->h_length); 
     printf("Addr=%x\n",(unsigned int)server->h_addr_list); 
     addr = (unsigned char *) *(server->h_addr_list); 
     printf("Addr=%x\n", *iaddr); 
     while (*addr != 0) 
     { printf("Addr=%d\n", *addr); 
      addr++; 
     } 
     } 
     else printf("Server-Address not found\n"); 
    } 
    server_port = (short) atoi(argv[2]); 
    /* 
    * Fill in the structure "serv_addr" with the address of the 
    * server that we want to send to. 
    */ 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    if (dotnum == 3) 
     serv_addr.sin_addr.s_addr = inet_addr(server_ip_addr); 
    else 
     serv_addr.sin_addr.s_addr = *iaddr; 
    serv_addr.sin_port = htons(server_port); 
    /* 
    * Open a UDP socket (an Internet datagram socket). 
    */ 
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
     err_dump("client can't open datagram socket"); 
    /* 
    * Bind any local address for us. 
    */ 
    bzero((char *) &cli_addr, sizeof(cli_addr)); /* zero out */ 
    cli_addr.sin_family = AF_INET; 
    cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    cli_addr.sin_port = htons(0); 
    if (bind(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) 
     err_dump("client: can't bind local address"); 
    /* else printf("bind ist ok\n"); */ 
    dg_cli(stdin, sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); 
    close(sockfd); 
    exit (0) ; 
} 

есть также Makefile:

# this makefile uses your sources 
APPN=echoUDP # put your favorite program here 

# change these for different maschines and stages of development 
CFLAGS = -g -lnsl # build the symbol table for debugger 

# build the utilities 
utilities.o: utilities.c 
    $(CC) $(CFLAGS) -c utilities.c 

# build the client application 
$(APPN)client: inet.h utilities.o $(APPN)client.o 
    $(CC) $(CFLAGS) -o $(APPN)client utilities.o $(APPN)client.o $(LFLAGS) 

# build the server application 
$(APPN)serv: inet.h utilities.o $(APPN)serv.c 
    $(CC) $(CFLAGS) -o $(APPN)serv utilities.o $(APPN)serv.o\ 
    $(APPN)serv.c $(LFLAGS)    

и заголовочный файл inet.h:

/* Header-File fuer TCP und UDP 
* Letzte Aenderung: 02.04.2008 K. Felten 
* Definitions for TCP and UDP client/server programs. 
*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <strings.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <errno.h> 
#include <syslog.h> 

#define SERV_HOST_ADDR "127.0.0.1" /* host addr for server = localhost */ 
char *pname; 
void err_sys(char *errortext); 
void err_dump(char *errortext); 
void dg_echo(int sockfd, struct sockaddr *pcli_addr, int maxclilen); 
void dg_cli(FILE *fp, int sockfd, struct sockaddr *pserv_addr, int servlen); 

и, по крайней мере, коммунальные услуги.c

/* Modul mit Hilfsprogrammen fuer Socket-Beispiel 
* Letzte Aenderung: 02.04.2008 K. Felten 
*/ 
#include <stdio.h> 
#include <string.h> 
#include <syslog.h> 

char emesgstr[255] ={0}; 

/* Print the UNIX errno value 
* We must append it to the end of the e,mesgstr[] array. 
*/ 
my_perror() 
{ 
    register int len; 
    char   *sys_err_str(); 
    len = strlen(emesgstr); 
    sprintf(emesgstr + len, " %s", sys_err_str()); 
} 

extern int errno;   /* UNIX error number */ 
extern int sys_nerr;  /* # of error message strings in sys table */ 
extern char *sys_errlist[]; /* the system error message table */ 

/* Return a string containing sme additional operating-system 
* dependet information. 
*/ 
char *sys_err_str() 
{ 
    static char msgstr[200]; 
    if (errno != 0){ 
     if (errno > 0 && errno < sys_nerr) 
     sprintf(msgstr,"(%s)", sys_errlist[errno]); 
     else 
     sprintf(msgstr,"(errno = %d)", errno); 
    } 
    else msgstr[0] = '\0'; 
    return(msgstr); 
} 

#define syslog(a,b) fprintf(stderr,"%s\n", (b))  
err_sys(errortext) 
char *errortext; 
{ 
    fprintf(stderr,"%s\n", errortext); 
    my_perror(); 
    syslog(LOG_ERR, emesgstr); 
    return(1); 
} 

err_dump(errortext) 
char *errortext; 
{ 
    fprintf(stderr,"%s\n", errortext); 
    my_perror(); 
    syslog(LOG_ERR, emesgstr); 
    return(1); 
} 
/* 
******************************************************************************* 
* Read "n" bytes from a descriptor. 
* Use in place of read() when fd is a stream socket. 
******************************************************************************* 
*/ 
int readn(fd, ptr, nbytes) 
register int fd; 
register char *ptr; 
register int nbytes; 
{ 
    int nleft, nread; 
    nleft = nbytes; 
    while (nleft > 0){ 
    nread = read(fd, ptr, nleft); 
    if (nread < 0) 
     return(nread); /* error, return < 0 */ 
    else if (nread == 0) 
     break; /* EOF */ 
    nleft -= nread; 
    ptr += nread; 
} 
return(nbytes - nleft); /* return >= 0 */ 
} 
/* 
******************************************************************************* 
* Read a stream socket one line at a time, and write each line back 
* to the sender. 
* 
* Return when the connection is terminated. 
******************************************************************************* 
*/ 
#define MAXLINE 512 
str_echo(sockfd) 
int sockfd; 
{ 
    int n; 
    char line[MAXLINE]; 
    char line2[MAXLINE]; 
    for (; ;) { 
    n = readline(sockfd, line, MAXLINE); 
    if (n == 0) 
     return; /* connection terminated */ 
    else if (n < 0) 
      err_dump("str_echo: readline error"); 
    strcpy(line2, "TCP-Echo=>"); 
    strcat(line2, line); 
    /* puts(line2); Testausgabe */ 
    n = strlen(line2); 
    if (writen(sockfd, line2, n) != n) 
     err_dump("str_echo: writen error"); 
    } 
} 
/* 
------------------------------------------------------------------------------ 
The following function is used by the three connection-oriented clients: 
------------------------------------------------------------------------------ 
* Read the contents of the FILE *fp, write each line to the 
* stream socket (to the server process), then read a line back from 
* the socket and write it to the standard output. 
* 
* Return to caller when an EOF is encountered on the input file. 
*/ 
#include <stdio.h> 
#define MAXLINE 512 
str_cli (fp, sockfd) 
register FILE *fp; 
register int sockfd; 
{ 
    int n; 
    char sendline[MAXLINE], recvline[MAXLINE + 1]; 

    while (fgets(sendline, MAXLINE, fp) != NULL) { 
     n = strlen(sendline); 
     if (writen(sockfd, sendline, n) != n) 
     err_sys("str_cli: writen error on socket"); 
     /* 
     * Now read a line from the socket and write it to 
     * our standard output. 
     */ 
     n = readline(sockfd, recvline, MAXLINE); 
     if (n < 0) 
     err_dump("str_cli: readline error"); 
     fputs(recvline, stdout); 
    } 
    if (ferror (fp)) 
     err_sys("str_cli: error reading file"); 
} 
/* 
------------------------------------------------------------------------------ 
The following function is used by the three connectionless servers. By passing 
address of the actual socket address structure to this function, it works with 
all protocol families. Since the size of the structure can differ between 
protocol families also pass its size to this function, as it is needed for the 
recvfrom system call. 
------------------------------------------------------------------------------ 
* Read a datagram from a connectionless socket and write it back to 
* the sender. 
* 
* We never return, as we never know when a datagram client is done. 
*/ 
#include <sys/types.h> 
#include <sys/socket.h> 
#define MAXMESG 2048 
dg_echo(sockfd, pcli_addr, maxclilen) 
int sockfd; 
struct sockaddr *pcli_addr; /* ptr to appropriate sockaddr XX structure */ 
int maxclilen;   /* sizeof(*pcli_addr) */ 
{ 
    int n, clilen; 
    char mesg[MAXMESG]; 
    char mesg2[MAXMESG]; 

    for (; ;){ 
     clilen = maxclilen; 
     n = recvfrom(sockfd, mesg, MAXMESG, 0, pcli_addr, &clilen); 
     if (n < 0) 
     err_dump("dg_echo: recvfrom error"); 
     /* Protokollausgabe */ 
     mesg[n] = 0; /* String-Laenge begrenzen */ 
     printf("UDP-Server-recvfrom:%slng=%d\n", mesg, n); 
     /* Manipulation der Zeilen */ 
     strcpy(mesg2, "UDP-Echo=>"); 
     strcat(mesg2, mesg); 
     n = strlen(mesg2); 
     if (sendto(sockfd, mesg2, n, 0, pcli_addr, clilen) != n) 
    err_dump("dg_echo: sendto error"); 
    } 
} 
/* 
------------------------------------------------------------------------------ 
The following function is for the connectionless clients. It is similar to the 
one for a connection-oriented client, with the writen calls replaced by sendto 
and the readn calls replaced by recvfrom. Also, we need the address of the 
actual socket address structure and its size for the datagram system calls. 
------------------------------------------------------------------------------ 
* Read the contents of the FILE *fp, write each line to the 
* datagram socket, then read a line back from the datagram 
* socket and write it to the standard output. 
* 
* Return to caller when an EOF is encountered on the input file. 
*/ 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#define MAXLINE 512 

dg_cli(fp, sockfd, pserv_addr, servlen) 
FILE *fp; int sockfd; 
struct sockaddr *pserv_addr; /* ptr to appropriate sockaddr_XX structure */ 
int servlen;   /* actual sizeof(*pserv_addrj */ 
{ 
    int n; 
    char sendline[MAXLINE], recvline[MAXLINE + 1]; 
    while (fgets(sendline, MAXLINE, fp) != NULL) { 
     n = strlen(sendline); 
     if (sendto(sockfd, sendline, n, 0, pserv_addr, servlen) != n) 
     err_dump("dg_cli: sendto error on socket"); 
     /* 
     * Now read a message from the socket and write it to 
     * our standard output. 
     */ 
     n = recvfrom(sockfd, recvline, MAXLINE, 0, 
          (struct sockaddr *) 0, (int *) 0); 
     if (n < 0) 
     err_dump("dg_cli: recvfrom error"); 
     recvline[n] = 0; /* null terminate */ 
     fputs(recvline, stdout); 
    } 

    if (ferror(fp)) 
    err_dump("dg_cli: error reading file"); 
} 
/* 
------------------------------------------------------------------------------ 
The following function writes to a stream socket: 
------------------------------------------------------------------------------ 
* Write "n" bytes to a descriptor. 
* Use in place of write() when fd is a stream socket. /* 
*/ 
int writen(fd, ptr, nbytes) 
register int fd; 
register char *ptr; 
register int nbytes; 
{ 
    int nleft, nwritten; 
    nleft = nbytes; 
    while (nleft > 0) { 
     nwritten = write(fd, ptr, nleft); 
     if (nwritten <= 0) 
     return(nwritten); /* error */ 
     nleft -= nwritten; 
     ptr += nwritten; 
    } 
    return(nbytes - nleft); 
} 
/* 
------------------------------------------------------------------------------ 
We use the following function to read a line from a stream socket. In our 
examples we'll be exchanging Unix text lines between the client and server. 
------------------------------------------------------------------------------ 
* Read a line from a descriptor. Read the line one byte at a time, 
* looking for the newline. We store the newline in the buffer, 
* then follow it with a null (the same as fgets(3)). 
* We return the number of characters up to, but not including, 
* the null (the same as strlen(3)). 
*/ 
int readline(fd, ptr, maxlen) 
register int fd; 
register char *ptr; 
register int maxlen; 
{ 
    int n, rc; 
    char c; 
    for (n = 1; n < maxlen; n++) { 
     if ((rc = read(fd, &c, 1)) == 1){ 
     *ptr++ = c; 
     if (c == '\n') 
      break; 
     } 
     else if (rc == 0) { 
       if (n == 1) 
       return(0); /* EOF, no data read */ 
       else 
       break; /* EOF, some data was read */ 
      } 
      else 
       return(-1); /* error */ 
    } 
    *ptr = 0; 
    return(n); 
} 

если я пытаюсь сделать echoDUPclient я получаю следующее сообщение об ошибке:

cc -g -lnsl  echoUDPclient.c -o echoUDPclient 
/tmp/cclsBda6.o: In function `main': 
/home/hannes/Dokumente/0_university/20_netzwerkprogrammierung/echo/echoUDP/echoUDPclient.c:81: undefined reference to `err_dump' 
/home/hannes/Dokumente/0_university/20_netzwerkprogrammierung/echo/echoUDP/echoUDPclient.c:90: undefined reference to `err_dump' 
/home/hannes/Dokumente/0_university/20_netzwerkprogrammierung/echo/echoUDP/echoUDPclient.c:92: undefined reference to `dg_cli' 

с делают утилиты я получаю:

cc -g -lnsl -c utilities.c 
utilities.c:23:14: Fehler: In Konflikt stehende Typen für »sys_errlist« 
/usr/include/i386-linux-gnu/bits/sys_errlist.h:28:30: Anmerkung: Vorherige Deklaration von »sys_errlist« war hier 

(означает confilct из sys_errlist и предыдущее заявление в sys_errlist.h)

В Solaris эта работа для sholud, но это не было на моем Linux. Итак, что мне нужно изменить?

ответ

2

Ваш первый звонок cc жалуется на неопределенные ссылки, так как вы не указали компоновщику, где найти объектный файл utilities.o. Скажите компоновщику (добавив utilities.o к вызову cc) или просто вставьте Makefile.

Согласно моим файлам Linux, sys_errlist имеет тип char **, а вы определяете char *sys_errlist[] в утилитах.c. Стоит отметить, что sys_errlist устарел, и вместо этого вы должны использовать strerror().

Это дает по крайней мере, два варианта:

  • либо исправить ваше определение sys_errlist, например, удалив его полностью и опираясь на stdio.h правильно отгадать
  • заменить весь sys_errlist материал с надлежащей strerror() ошибки отчетности

Замечание, что может быть проще придумать свой собственный UDP эхо-клиент/сервер вместо переноса реализации Solaris. Кроме того, вы должны правильно пометить свои домашние вопросы как таковые.

Grüße aus dem Saarland :)