Unix網絡編程學習日記

今天開始拜讀《Unix網絡編程》。找到的源代碼在Linux下有各種問題,最後決定還是自己從頭寫比較好。

從第一個時間服務程序開始學習。今天先看一下主要的頭文件的作用。

在common.h中(參照 unp.h 自己寫的,包含常用頭文件和一些常量定義,用着方便),有以下的頭文件:

sys/types.h 

此頭文件是系統類型的定義,如:int8_t int16_t int32_t int64_t等等

sys/socket.h

這是socket的接口,在其中引入bits/socket.h,其中定義了各種常量。

netinet/in.h

定義了各種地址結構體和常量。

arpa/inet.h

定義了地址轉換的函數。

其它的頭文件是常用頭文件。還有一些常數定義以及結構體的簡稱。以後會隨時添加。

在error.c和error.h中,聲明和定義了常用的錯誤輸出。

目錄結構爲下圖所示:


以下是源程序:

daytimecpcli.c:

#include "common.h"
#include "error.h"

int main(int argc, char **argv)
{
	int sockfd, n;
	char recvline[MAXLINE + 1];
	struct sockaddr_in servaddr;

	if (argc != 2)
		err_quit("usage: ./daytimecpcli.c <IP address>");
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port   = htons(IPPORT_DAYTIME);

	if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
		err_quit("inet_pton error for %s", argv[1]);

	if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
		err_sys("connect error");

	while ((n = read(sockfd, recvline, MAXLINE)) > 0)
	{
		recvline[n] = 0;
		if (fputs(recvline, stdout) == EOF)
			err_sys("fputs error");
	}
	if (n < 0)
		err_sys("read error");

	exit(0);
}
common.h:

#ifndef __COMMON_H
#define __COMMON_H

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define MAXLINE 4096
#define SA struct sockaddr

#endif

error.h:

#ifndef __MYERROR_H
#define __MYERROR_H

#include <stdio.h>
#include <stdlib.h>

void err_ret(const char *fmt, ...);
void err_sys(const char *fmt, ...);
void err_dump(const char *fmt, ...);
void err_msg(const char *fmt, ...);
void err_quit(const char *fmt, ...);


#endif

error.c:

#include <errno.h>    /* for definition of errno */
#include <stdarg.h>   /* ANSI C header file */
#include "error.h"
#include "common.h"

static void err_doit(int, const char *, va_list);

void err_ret(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	err_doit(1, fmt, ap);
	va_end(ap);

	return;
}

void err_sys(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	err_doit(1, fmt, ap);
	va_end(ap);

	exit(1);
}

void err_dump(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	err_doit(1, fmt, ap);
	va_end(ap);

	abort();
	exit(1);
}

void err_quit(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	err_doit(0, fmt, ap);
	va_end(ap);

	exit(1);
}

void err_msg(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	err_doit(0, fmt, ap);
	va_end(ap);

	return;
}

static void err_doit(int errnoflag, const char *fmt, va_list ap)
{
	int errno_save;
	char buf[MAXLINE];

	errno_save = errno;
	vsprintf(buf, fmt, ap);
	if (errnoflag)
		sprintf(buf+strlen(buf), ": %s", strerror(errno_save));
	strcat(buf, "\n");
	fflush(stdout);
	fputs(buf, stderr);
	fflush(stderr);

	return;
}

我將error.c製作成了名爲liberr.a的靜態庫,爲以後連接方便做準備。所以,sock目錄下的Makefile內容如下:

all: liberr.a

liberr.a: liberr.o
	ar rv liberr.a liberr.o
liberr.o: error.c error.h common.h
	gcc error.c -c -o liberr.o

clean:
	rm -rf *.o *.a

intro目錄下的Makefile內容如下:

targets = daytimecpcli
cc = gcc
INCLUDES = -I"../sock/"
LIBS = -L"../sock/"

all: $(targets)

daytimecpcli: daytimecpcli.c ../sock/liberr.a
	$(cc) -o daytimecpcli daytimecpcli.c $(LIBS) -lerr $(INCLUDES)
../sock/liberr.a: ../sock/error.c ../sock/error.h ../sock/common.h
	cd ../sock && make

clean:
	rm -rf $(targets) *.o

在打開書上的程序daytimetcpsrv時,程序執行效果如下:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章