c - 在 Ubuntu 上使用 Solaris 中的 C 套接字

标签 c sockets ubuntu solaris

以下 C 代码是针对Solaris 编写的。现在我必须将它移植到 ubuntu linux:

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

如果我尝试 make 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 与 sys_errlist.h 中先前的声明冲突)

在 Solaris 上这应该可以工作,但在我的 Linux 上却不行。那么我需要修改哪些内容?

最佳答案

您第一次调用 cc 会提示 undefined reference ,因为您忽略了告诉链接器在哪里可以找到 utilities.o 对象文件。告诉链接器(通过将 utilities.o 添加到 cc 调用)或直接使用 Makefile。

根据我的 Linux 联机帮助页,sys_errlist 的类型为 char **,而您在utilities.c 中定义 char *sys_errlist[]。值得注意的是,sys_errlist 已弃用,您应该使用 strerror() 代替。

这至少给你两个选择:

  • 修改您对 sys_errlist 的定义,例如完全删除它并依靠 stdio.h 正确声明它
  • 用正确的 strerror() 错误报告替换整个 sys_errlist 内容

顺便说一句,提出自己的 UDP 回显客户端/服务器可能比移植 Solaris 实现更容易。另外,您应该正确标记您的作业问题。

Grüße aus dem Saarland:)

关于c - 在 Ubuntu 上使用 Solaris 中的 C 套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9884868/

相关文章:

c - 模拟 printf 堆栈弹出

c - 使用register_chrdev动态分配主编号时,保留256个次编号有什么意义吗?

linux - 将自定义 Hook 添加到使用 Docker 安装的 Gitlab

c - clang 中是否有固定宽度的 float 类型?

c++ - 错误(文件)== 32

C#:如何处理乱序的TCP数据包?

sockets - 在IP层面, "leave the connection open"是否具有特定的技术含义——例如存储IP映射条目的中间网关?

c - 使用 C (Ubuntu) 的套接字编程中的段错误

java - Tomcat无法连接8005端口

php - 无法在 Ubuntu 21.04 上安装 PHP8.0 和 php8.0-pgsql