这节我们开始学习网络方面的实践并追踪进入内核,因为网络范围很广我们只讲socket方面的知识,由socket编程进入内核,我是无名小卒,写这些文章是为了引领朋友们如何渗透内核的工作原理,起到导航的作用,可能前面讲的不是非常的透彻,那是假定朋友们有一定操作系统知识并且具备C语言基础上进行的,回到socket话题,因为其大而且复杂,我们将会大篇幅来学习他,特别是近日我在一个项目中涉及到socket编程,所以更会具体一些实际的操作,顺便说一句,现在社会真的是太浮躁,尤其是我接触的很多朋友中,大多数是带着应付公事的心情做事和学习,心中的理想非常远大,有说不完的实现方法和措施,但是真正去做的人实在是少,从中可以看出心态对于事业的重要性,有些事不便直说只能说整个社会的风气是每况日下,就象企业为什么一边在天天招工程师,另一边却把人才冷落在一角,招进来就是为了放在那里充门面的吧,很多企业看似技术含量很高,产品种类繁多,市场很大,人力充沛,其实内骨里却是OEM别人的技术和产品,充其量贴上一个自己的商标而已,不过这样竟然也能生存下去,为什么?因为他经营的不是产品是关系,有关系就能生存就能壮大,现在的企业都在学习这些,都想迅速在市场上赚到钱,都采取“拿来主义”即拿别人的技术和产品赚自己的钱,深层看一下,哪来的钱可赚?哪来的利可图?这是社会的“潜规则”,企业都这样了,何况人呢,所以就出现了经营人才的人才,有点绕嘴,不过是现实,也就是说有专门把人才拿来当商品OEM给别人的,这样,哪边企业需要就哪边转借使用,不是技术上和能力上的使用,就象很多企业要博士学历,他要的是人家的文凭用来充门面的,同样,人才也是充门面的了,借给你充门面,这样下去,不要说人才冷遇了,企业也成了一个空壳,于是形成了“国内OEM国外的,北方企业OEM南方企业的,发展企业OEM发达企业的”说到这里可能有朋友扔板砖了“OEM不好吗?能学到很多东西”,学到东西那就引进技术。又有甚者说“企业就是赚钱的,不赚钱不成了搞研究所了吗”,企业目的是赚钱,但不是赚眼前钱。大家都OEM过来OEM过去,如此简单就赚到钱了,谁还搞技术,你将来OEM什么呢?同时眼前的社会风气是一切向“钱”看,当年的反对享乐主义不提了,拜金主义盛行了,还有多少人能搞技术,还有多少人能坚持下去?警醒吧,朋友们,把心收一收,擦亮眼睛,为了今后自己长远的发展也为了将来国家真正繁荣还是踏实搞好技术吧,不过,请不要抄我的文章去做论文也不要OEM拿去印成书^_^,好了进入我们今天的应用程序中吧
我们使用这个练习创建一个没有名称的客户端的socket然后连接服务器端的server_socket
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <sys/un.h> #include <unistd.h> #include <stdlib.h>
int main() { int sockfd; int len; struct sockaddr_un address; int result; char ch = 'A';
我们在这里创建一个socket sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
为socket赋名称,要与server端的名称相同
address.sun_family = AF_UNIX; strcpy(address.sun_path, "server_socket"); len = sizeof(address);
现在连接服务器端的也就是server那面的socket
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1) { perror("oops: client1"); exit(1); }
现在我们可以在客户端读写socket了
write(sockfd, &ch, 1); read(sockfd, &ch, 1); printf("char from server = %c\n", ch); close(sockfd); exit(0); }
|
上面这个程序就是基于客户端的一个socket,socket的概念请朋友们查询资料,我们这里只对他的执行过程感兴趣,现在我们有一个客户端的socket,还需要一个服务器端的socket,现在这个客户端的socket还不能正常运行,必须要与服务器端的socket结合才行
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <sys/un.h> #include <unistd.h> #include <stdlib.h>
int main() { int server_sockfd, client_sockfd; int server_len, client_len; struct sockaddr_un server_address; struct sockaddr_un client_address;
移除旧的socket,防止冲突,然后创建一个未命名的socket
unlink("server_socket"); server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
为创建的这个socket赋名称,与客户端的保持一致的名称
server_address.sun_family = AF_UNIX; strcpy(server_address.sun_path, "server_socket"); server_len = sizeof(server_address); bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
创建一个连接队列等待客户端来链接
listen(server_sockfd, 5); while(1) { char ch;
printf("server waiting\n");
接受连接
client_len = sizeof(client_address); client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len); 开始与客户端读写的操作
read(client_sockfd, &ch, 1); ch++; write(client_sockfd, &ch, 1); close(client_sockfd); } }
|
运行看效果
有了这个服务器端的程序我们可以做socket的实验了
[root@localhost qinj]# ./server1 & [root@localhost qinj]# ./client1 char from server = B
|
我们看到服务器端在socket接受到客户端的连接后,读到客户端发送过来的字符A后,然后使它自增后变成B再发送给客户端,客户端收到后打印到了屏幕上。上面这个socket程序是针对本机内的unix范围的socket,我在写项目时曾经没有注意地址的关键事项,unix范围内的socket仅限于同一台计算机内的socket进程通讯,他使用的地址结构是struct sockaddr_un,而在互联网的socket要使用的数据结构则是struct sockaddr_in,由于这个失误会造成对项目在本机上调试通过但是换到另一台PC上就不能成功了,看到网上很多教程都是基于struct sockaddr_un的,所以请朋友们一定要注意,再者还要注意对地址和端口的初始化赋值操作一个是inet_addr()函数来初始化值另一个是htons()来初始化值,这二者针对的是不同用途的socket,前者是对本机IP地址的,另后者则是正好相反。
对上面的程序我们可以看出客户端与服务器端有几点不同,他们的初始声明是相同的,但是服务器端需要先使用listen来监听客户端的连接,等连接到来后服务器端再能过accept来接收链接并取得客户端socket的地址,所以服务器端用二个socket地址结构变量,而客户端只有一个服务器端的地址结构变量,而且客户端只要建立连接就可以对socket操作了。今天先写至此,明天我们看本机IP地址内的socket进程练习。