linuxc网络编程(linux网络编程基础)

http://www.itjxue.com  2023-02-11 01:25  来源:未知  点击次数: 

想在LINUX下学习C语言,该如何开始?

一、工具篇

“公欲善其事,必先利其器”。编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工具。

1、操作系统

在UNIX或Linux系统中学习C很方便,所以在开始您的学习旅程前请先选择一个UNIX或Linux操作系统,目前可供个人免费使用的UNIX或Linux系统有FreeBSD、RedHat Linux、SUSE Linux等,而且在安装包中还提供很多实用的工具,如:gcc, make等。

如果您一直使用Windows,身边又没有多余的机器安装UNIX,则可以使用VMware,通过VMware安装虚拟系统。

2、编译工具

目前绝大多数Unix或Lnux系统都提供CC或GCC编译器,最简单的cc命令格式如下:

cc -o hello hello.c

在unix shell环境中敲入上面的代码会将hello.c程序编译成可执行文件hello。

3、make工具

如 GNU make、System V make 和 Berkeley make 是用来组织应用程序编译过程的基本工具,但是每个 make 工具之间又有所不同。

大部分UNIX和Linux程序都是通过运行make来编译的。

make工具会读取一个包含指令的文件(这个文件的名字通常都是 makefile 或 Makefile,不过后文中我们统一称之为 “makefile”),并执行各种操作来编译程序。

4、调试工具

最简单的调试工具:为你的程序添加打印语句,在你对程序的运行机制有了一定的了解后,你可以实用一些工具帮助你进行调试,当然你得学习一下这些工具得使用,如:dbx,gdb等。

还有一些内存工具可以帮你查找内存泄漏或缓冲区溢出等一些问题,如:memwatch,yamd等。

5、其他工具

1)vi或vim

Unix下文本编辑器。主要靠一堆命令来编辑文本文件,学Unix编程最好熟悉并熟练使用vi编辑器。

当然在实际工作中,你可能需要一个集成编码环境或一个功能强大的图形化编辑工具。

提供一个中文的vim在线手册:

2)Secure shell/putty

一个支持ssh协议得客户端工具,多数情况下用来连接linux系统。

二、书籍篇

“书是人类进步得阶梯”。学习一门新的知识,当然要选择几本适合自己得书籍,下面介绍一些我自己学习C语言使用过的书籍:

1.《C primer plus》

推荐理由:适合作为入门书和基本函数查询得参考资料。本书最新版为第五版,以ANSI C99为标准详细介绍了C语言。

2.《The C programming_Language》

推荐理由:C语言之父得作品权威性毋庸置疑。虽然书籍出版时间比较老,好像也没更新,不过仍不失为经典书籍,网上有这本书得英文电子版提供下载。

3.《C 专家编程》

推荐理由:本书可以帮助有一定经验的C程序员成为C编程方面的专家,最关键的是本书寓教于乐,让你充分享受编程的乐趣。

4.《C缺陷与陷阱》

推荐理由:书中所揭示的知识能帮助您绕过C语言自身得陷阱和缺陷,减少代码中许多常见的Bug。

5.《unix环境高级编程》

推荐理由:既然是UNIX环境下C编程,就不得不说说UNIX编程书籍。

Stevens先生的《unix环境高级编程》是我竭力推荐的,也是我的案头必备(如果对网络编程有兴趣的,可以学习一下Stevens先生的《UNIX网络编程》两卷,如果觉得还不过瘾,可以再看看《TCP/IP详解》三卷)。

6.《计算机编程艺术》

推荐理由:算法大师得呕心沥血之作。计划出版五卷书,目前好像已出版3卷。对算法有兴趣得可以研究一下。

三、过程篇

1.学习C语法

语法的学习对于一个具有编程底子的来说,就很轻松了;即使你以前没有学习过其他编程语言,我相信有2个星期,你也能轻松搞定。

需要注意的是,不要太纠缠于语言的细节,比如:运算符优先级与结合性的问题等。

2.学习C标准库

ANSI C库把函数分为不同的组,每个组都具有与之相关的头文件。C语言标准库相对于其他语言,比如C++,Java来说是非常短小精悍的,但首先应着重对以下库进行学习:

ctype.h:字符处理

math.h:数学库

stdio.h:标准I/O库

stdlib.h:通用工具库

string.h:字符串处理

time.h:时间和日期

如果想了解完成的ANSI C库,你可以购买相关的书籍,这些书籍一般会详细介绍每个函数的用户和一些注意点;当然你也可以登陆 ... amp;page=index.html获取ANSI C库详细信息。

3.攻克C的难点

1)C语言声明:

C语言的声明确实让我觉得恐怖,比较晦涩难懂,而且声明的形式和使用的形式还类似。比如如下的声明恐怕就连很多熟悉C多年的程序员也不是一眼就能看出来的:

char * const * (*next)();

那么有没有一种好的记忆方法或规则来搞清楚呢,好像没有,如果有的话也不是这样折磨人了。不过可以看看《C专家编程》第三章的内容,或许你会有所收获。

也只能多学多练了,所谓熟能生巧嘛,希望这个问题不要在你的心灵上留下阴影。

2)数组与指针:

数组与指针的关系,在标准中并没有作很详细的规定,而且好多C入门的书籍在这个问题上并没有给出很详细的说明,所以会给人造成很多误解。

对于这个问题,你可以参考《C缺陷与陷阱》4.5节和《C专家编程》第4,9,10章,相信你这里面的内容搞透彻,以后就不会再被这个问题搞迷惑。

3)指针与内存:

如果你以后编写规模较大的程序,你可能发现这个问题可能会是你最大的烦恼,而且可能会是你消耗最多调试时间的事项。

4)C版本的问题:

你得特别小心该问题,最好不要在你的程序中混合使用不同版本C的特性,否则会给你带来很迷惑的问题。如果一定要用,你最好清楚自己在做什么。

还有一些其他C中的难点和容易错误的地方,可以学习前人的一些经验。以下是一个c FAQ的链接地址,相信在这篇文档中有你需要的大部分问题的解决方法。

4. UNIX环境编程

学习了以上内容之后,我相信,你就可以进行unix环境编程了。不过你可能需要对操作系统理论有一点点的了解,这样学起来会比较轻松一些。

Unix环境编程,你应该着重IO和进程两大块内容。

《Unix环境高级编程》中对Unix环境编程有着非常详细且深入的论述,而且书中有大量实用性例子程序,不过可能得花上几个月得时间,好好啃一啃了。

在扎实掌握以上内容,不代表你得C语言学习支路已经完成,相反,才刚刚开始。以后你需要用学到得知识去解决大量不同实际问题,在不断得实践过程中,你会近一步加深对C的理解。有了以上基础之后,你会发现,在实践过程中需要的其他知识,你会非常快速的掌握。

linux网络编程中如何实现服务器端多个read()和客户端write( )

TCP通信的模式如下图,比较固定,对着图编代码就可以了:

服务器的main函数:

int main(int argc, char **argv)

{

?int listenfd, connfd;

?pid_t childpid;

?socklen_t clilen;

?struct sockaddr_in cliaddr, servaddr; //IPv4 address

?/*socket*/

?listenfd = socket(AF_INET, SOCK_STREAM, 0);//创建一个TCP的socket

?if (-1 == listenfd) {

? perror("socket erro.");

? return -1;

?}

?/*bind*/

?//首先初始化server的IP地址和端口,然后再与刚刚创建的socket绑定

?bzero(servaddr, sizeof(servaddr));

?servaddr.sin_family = AF_INET;//设置协议簇

?servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定本机的网卡

?servaddr.sin_port = htons(1234);//绑定端口号,端口号可以随便取,大于1024就可以了

?if (-1 == bind(listenfd, (struct sockaddr *)servaddr, sizeof(servaddr))) {

? perror("bind error.");

? return -1;

?}

?/*listen*/

?//到这里已经有了一个绑定了IP地址和端口号的socket了,但是这个socket是个主动的socket,

?//而作为server需要的是一个等待别的接入的被动的socket,所以得调用listen将这个socket设置为监听状态

?//第二个参数表示服务器正在处理客户接入时的等待队列长度。

?if (-1 == listen(listenfd, 10)) {

? perror("listen error.");

? return -1;

?}

?while (1) {

? clilen = sizeof(cliaddr);

? //调用accept等待客户的接入,同时accept会用第二个参数返回客户的IP地址,

? //通过第三个参数返回IP地址的实际大小,同时这个参数也是个值-结构参数,也就是

? //在传递这个参数的时候,先给这个参数一个初始的值,然后函数中会根据具体的情况修改这个值,

? //所以这里传递的是指针。

? //当客户接入后,将返回一个成功和客服连接的socket描述符,通过读写这个socket即可实现和客户的通信了

? connfd = accept(listenfd, (struct sockaddr *)cliaddr, clilen);

? if (-1 == connfd) {

? ?if (EINTR == errno)

? ? continue;

? ?perror("accept error.");

? ?return -1;

? }

? //通过fock创建子进程来处理客户请求,这里只是显示客户的IP地址、端口号和发送的文字,

? //并将客户发送的文字回传给客户。

? if (0 == (childpid=fork())) {//fock返回0 说明是子进程

? ?//这里并没有关闭服务器的监听socket,只是将其引用计数减一,因为fork出来的子进程对父进程做了拷贝,

? ?//所以这个监听socket的引用计数将由1变成2,而内核只有在一个socket的引用计数变为0才回去关闭它

? ?close(listenfd);

? ?//通过和客户连接的socket和客户通信? ? ?

? ?str_echo(connfd, cliaddr);

? ?return 0;

? }

? //父进程将和客户连接的socket的引用计数减一,同样并没有关闭这个socket

? close(connfd);

?}

?return 0;

}

服务器处理客户请求:

#define BSIZE 100

void str_echo(int sockfd, struct sockaddr_in cliaddr)

{

?ssize_t n;

?char buf[BSIZE];

?

?while ((n=read(sockfd, buf, BSIZE))) {//读取客户发送的信息

? buf[n] = '\0';

? printf("IP: %s, PORT: %d: %s\n", \

? ? inet_ntoa(cliaddr), ntohs(cliaddr.sin_port), buf); //输出信息

? n_write(sockfd, buf, n);//将受到的信息发送回客户,n_write的实现下面给出

?}

}

客户端程序相对简单:

int main(int argc, char **argv)

{

?int sockfd;

?struct sockaddr_in servaddr;

?

?if (2 != argc) {

? printf("usage: ./client 127.0.0.1");//

? return -1;

?}

?/*socket*/

?sockfd = socket(AF_INET, SOCK_STREAM, 0);?//创建一个socket

?if (-1 == sockfd) {

? perror("socket error.");

? return -1;

?}

?/*connect*/

?//首先初始化要连接的服务器的IP地址和端口号,然后调用connect去连接这个服务器

?bzero(servaddr, sizeof(servaddr));

?servaddr.sin_family = AF_INET;

?servaddr.sin_port = htons(1234);

?inet_pton(AF_INET, argv[1], servaddr.sin_addr);

?if (-1 == connect(sockfd, (struct sockaddr *)servaddr, sizeof(servaddr))) {

? perror("connect error.");

? return -1;

?}

?//连接成功后就可以通过这个socket来和服务器通信了

?str_cli(stdin, sockfd);

return 0;

}

n_write 和 readline

/*write n bytes to fd*/

ssize_t n_write (int fd, void *buf, size_t n)

{

?size_t nleft = n;

?ssize_t nwriten;

?char *bufp = buf;

while (nleft 0) {

? if ((nwriten = write (fd, bufp, nleft)) = 0) {

? ?if (EINTR == errno)

? ? nwriten = 0;

? ?else

? ? return -1;

? }

nleft -= nwriten;

? bufp += nwriten;

?}

return n;

}

/*read line from fd*/

ssize_t readline (int fd, void *buf, size_t maxlen)

{

?ssize_t n, rc;

?char c, *bufp;

bufp = buf;

?for (n = 1; n maxlen; n ++) {

again:

? if (1 == (rc = read (fd, c, 1))) {

? ?*bufp ++ = c;

? ?if ('\n' == c)

? ? break;? /*newline is stored*/

? } else if (rc == 0) {

? ?*bufp = 0;

? ?return (n - 1);? /*EOF, n-1 bytes were read*/

? } else {

? ?if (EINTR == errno)?/*interrupt*/

? ? goto again;

? ?return -1;? /*Erro, set the errno by read ()*/

? }

?}

?*bufp = 0;

?return n;

}

运行结果:

因为客户端没有指定IP地址和端口,所以其IP和端口都是内核随机分配的。

linux下C语言用socket网络编程怎么计算传输速度?

这要你的通信程序协商一个协议,比如定义一个通信结构体,传文件的时候,一开始发送结构体的信息过去,告诉对端你的文件总大小,然后,传输过程中,统计已经收到或者发送的数据,做个除法就得到速率了。

具体这类协商,你可以自己随便想,也可以借鉴现有的比较好的一些设计,有些考虑断点续传的技术,还有压缩的,看你代码也不需要考虑吧。

(责任编辑:IT教学网)

更多

推荐Illustrator教程文章