2012-03-27 47 views
0

爲solaris編寫了以下c代碼。現在我已經將它移植到Ubuntu Linux操作系統:在Ubuntu上使用Solaris上的C套接字

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) ; 
} 

也有一個生成文件:

# 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' 

與make實用程序我得到:

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 

(指使用sys_errlist的confilct和sys_errlist.h先前聲明)

在Solaris上,這個sholud工作,但它沒有在我的linux上。那麼我需要修改哪些東西?

回答

2

您的第一個電話cc抱怨未定義的參考,因爲您省略了告訴鏈接器在哪裏找到utilities.o目標文件。告訴鏈接器(通過在cc調用中添加utilities.o)或者簡單地使用Makefile。

根據我的Linux手冊頁,sys_errlist具有類型char **,當你在utilities.c定義char *sys_errlist[]。值得注意的是,sys_errlist已被棄用,您應該改用strerror()

這讓你至少有兩個選項:

  • 要麼解決您的sys_errlist定義,例如通過完全刪除,並依靠stdio.h正確聲明它
  • 更換整個sys_errlist東西適當strerror()錯誤報告

在旁註,它可能更容易拿出自己的UDP回聲客戶機/服務器而不是移植Solaris實現。此外,你應該正確地標記你的作業問題。

Grüßeaus dem Saarland :)