Chinaunix首页 | 论坛 | 博客
  • 博客访问: 134450
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 633
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-05 11:44
文章存档

2014年(14)

我的朋友

分类: LINUX

2014-09-09 01:08:16

一、套接字地址结构
进行套接字编程需要指定套接字的地址作为参数,不同的协议族有不同的地址结构定义方式。
通常使用sockaddr开头,每个协议族有一个唯一的后缀。
1、通用的套接字地址结构
  1. struct sockaddr{            //套接字地址结构
  2.     sa_family_t sa_family; //协议族
  3.     char sa_data[14];        //协议族数据
  4. };
2、以太网套接字地址结构
  1. struct sockaddr_in{            //以太网套接字地址结构
  2.     u8 sin_len;                //结构struct sockaddr_in的长度,16
  3.     u8 sin_family;            //通常为AF_INET
  4.     u16 sin_port;            //16位的端口号,网络字节序
  5.     struct in_addr sin_addr;//IP地址32位
  6.     char sin_zero[8];        //未用
  7. };
  8. struct in_addr{        //IP地址结构
  9.     u32 s_addr;        //32位IP地址,网络字节序
  10. };

二、TCP网络编程流程
TCP网络编程有两种模式,分别是服务器模式和客户端模式。
服务器模式:创建一个服务程序,等待客户端用户的连接,接收用户请求,根据用户的请求进行处理;
客户端模式:根据服务器的地址和端口进行连接,向服务器发送请求并对服务器的相应进行数据处理。

1、服务器端设计模式
1)套接字初始化socket()
2)套接字与端口的绑定bind()
3)设置服务器的监听listen()
4)接收客户端连接accept()
5)接收和发送数据read()\write()
6)套接字关闭close()

2、客户端设计模式
1)套接字初始化socket()
2)连接服务器connect()
3)读写网络数据read()\write()
4)套接字关闭close()

三、套接字接口函数
1、socket()
socket()函数创建一个套接字文件描述符
  1. 函数原型:
  2. #include<sys/types.h>
  3. #include<sys/socket.h>
  4. int socket(int domain,int type,int protocol);
  5. 参数说明:
  6. domain:网络通信域
  7.     PF_UNIX,PF_LOCAL 本地通信
  8.     PF_INET ipv4协议
  9.     PF_INET6 ipv6协议
  10.     PF_IPX IPX协议
  11.     PF_NETLINK 内核用户界面设备
  12.     PF_X25 x.25协议
  13.     PF_AX25 ax.25协议
  14.     PF_ATMPVC 原始ATM PVC访问
  15.     PF_APPLETALK appletalk协议
  16.     PF_PACKET 底层包访问
  17. type:套接字通信类型
  18.     SOCK_STREAM:TCP连接
  19.     SOCK_DGRAM:UDP连接
  20.     SOCK_SEQPACKET:序列化包
  21.     SOCK_RAW:原始网络协议访问
  22.     SOCK_RDM:提供可靠的数据报文,可能数据会有乱序
  23.     SOCK_PACKET:专用类型
  24. protocol:指定协议的特定类型
引用层函数socket()与内核函数的关系:
用户调用函数sock=socket(AF_INET,SOCK_stream,0),这个函数会调用系统调用函数sys_socket(AF_INET,SOCK_STREAM,0).
系统调用sys_socket()分为两个部分,一部分调用sock_create()函数生成内核socket结构,另一部分调用sock_map_fd()
函数与文件描述符绑定,将绑定的文件描述符值传给应用层。
内核sock结构
  1. struct socket{
  2.     socket_state state;//socket状态
  3.     unsigned long flags;//socket标志
  4.     const struct proto_ops *ops;//协议特定的socket操作
  5.     struct fasync_struct *fasync_list;//异步唤醒列表
  6.     struct file *file;//文件指针
  7.     struct sock *sk;//内部网络协议结构
  8.     wait_queue_head_t wait;//多用户时的等待队列
  9.     short type;//socket类型
  10. }
2、bind()
对套接字文件描述符进行地址和端口的绑定
  1. 函数原型:
  2. #include<sys/types.h>
  3. #include<sys_socket.h>
  4. int bind(int sockfd,const struct sockaddr *my_addr,socklen_t addrlen);
  5. 参数说明:
  6. sockfd:套接字文件描述符
  7. my_addr:地址结构指针
  8. addrlen:地址结构长度
应用层bind()函数和内核函数的关系
应用层函数bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))调用系统调用
sys_bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))。sys_bind()函数首先调用函数
sockfd_lookup_light()来获得文件描述符sockfd对应的内核struct sock结构,然后调用函数move_addr_to_kernel()
将应用层的参数my_addr复制进内核,放到address变量中。

3、listen()
初始化服务器可连接队列
  1. #include<sys/socket.h>
  2. int listen(int sockfd,int backlog);
  3. 参数说明:
  4. sockfd:套接字文件描述符
  5. backlog:等待队列中的客户端的长度
应用层listen()和内核层listen()的关系:
应用层的listen()函数对应于系统调用sys_listen()函数。sys_listen()函数首先调用sockfd_lookup_light()
获得sockfd对应的内核结构struct sock,得到backlog值。然后调用抽象的listen()函数(如AF_INET的listen()函数)
inet_listen()。inet_listen()函数首先判断是否合法的协议族和协议类型,然后更新socket的状态值为TCP_LISTEN,
然后为客户端的等待队列申请空间并设定监听端口。

4、accept()
接收客户端的请求。调用accept成功后会返回一个新的套接字文件描述符来表示客户端的连接。
  1. 函数原型:
  2. #include<sys/types.h>
  3. #include<sys/socket.h>
  4. int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
  5. 参数说明:
  6. sockfd:socket()函数创建的套接字文件描述符
  7. addr:客户端连接的地址结构
  8. addrlen:客户端地址结构长度
应用层accept()函数和内核函数的关系
应用层的accept()函数对应内核层的sys_accept()系统调用函数。函数sys_accept()查找文件描述符对应的内核socket
结构、申请一个用于保存客户端连接的新内核socket结构、执行内核接收函数、获得客户端的地址信息、将连接的客户
端地址信息复制到应用层的用户、返回连接客户端socket对应的文件描述符。

5、connect()
连接指定参数的服务器。

点击(此处)折叠或打开

  1. 函数原型:
  2. #include<sys/types.h>
  3. #include<sys.socket.h>
  4. int connect(int sockfd,struct sockaddr *,int addrlen);
  5. 参数说明:
  6. sockfd:套接字文件描述符
  7. struct sockaddr:服务器地址结构指针
  8. addrlen:服务器地址结构长度
6、write()/read()
套接字的读写方式和普通文件的读写方式相同
int write(int sockfd,char *buf,int len);
int read(int sockfd,char *buf,int len);

7、close()
关闭套接字,释放资源
int close(int sockfd);

8、shutdown()
提供多种方式关闭连接,关闭双连接的一部分

点击(此处)折叠或打开

  1. #include<sys/socket.h>
  2. int shutdown(int s,int how);
  3. 参数说明:
  4. s:套接字文件描述符
  5. how:切断方式
  6.     SHUT_RD:切断读
  7.     SHUT_WD:切断写
  8.     SHUT_RDWD:切断读写
四、示例
1、服务器端程序server_tcp.c

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<strings.h>
  4. #include<sys/types.h>
  5. #include<sys/socket.h>
  6. #include<unistd.h>
  7. #include<linux/in.h>

  8. #define PORT 8888 //端口
  9. #define BACKLOG 5 //监听队列的长度

  10. //服务器对客户端的处理
  11. void process_conn_server(int s)
  12. {
  13.     ssize_t size=0;
  14.     char buffer[1024];
  15.     
  16.     for(;;)
  17.     {
  18.         size=read(s,buffer,sizeof(buffer));
  19.         if(size==0)
  20.         {
  21.             printf("read error\n");
  22.             return ;
  23.         }
  24.         sprintf(buffer,"%s bytes",size);
  25.         write(s,buffer,sizeof(buffer)+1);
  26.     }
  27.     close(s);
  28. }

  29. int main(int argc,char *argv[])
  30. {
  31.     int ss,cc;
  32.     struct sockaddr_in server_addr,client_addr;
  33.     int err;
  34.     pid_t pid;
  35.     
  36.     //创建流式套接字TCP
  37.     ss=socket(AF_INET,SOCK_STREAM,0);
  38.     if(ss<0)
  39.     {
  40.         printf("creat sock error\n");
  41.         return -1;
  42.     }
  43.     
  44.     //设置服务器地址
  45.     bzero(&server_addr,sizeof(server_addr));
  46.     server_addr.sin_family=AF_INET;
  47.     server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
  48.     server_addr.sin_port=htons(PORT);
  49.     
  50.     //绑定地址到套接字
  51.     err=bind(ss,(struct sockaddr *)&server_addr,sizeof(server_addr));
  52.     if(err<0)
  53.     {
  54.         printf("bind error\n");
  55.         return -1;
  56.     }
  57.     
  58.     //设置监听队列
  59.     err=listen(ss,BACKLOG);
  60.     if(err<0)
  61.     {
  62.         printf("listen error\n");
  63.         return -1;
  64.     }
  65.     
  66.     //主循环过程
  67.     for(;;)
  68.     {
  69.         int addrlen=sizeof(struct sockaddr);
  70.         //接收客户端连接
  71.         cc=accept(ss,(struct sockaddr *)&client_addr,&addrlen);
  72.         if(cc<0)
  73.         {
  74.             continue;
  75.         }
  76.         
  77.         //创建子进程
  78.         pid=fork();
  79.         if(pid==0)//子进程
  80.         {
  81.             close(ss);//关闭继承的父进程的服务器端套接字文件描述符
  82.             process_conn_server(cc);
  83.         }else{
  84.             close(cc);//父进程中关闭子进程的连接
  85.         }
  86.     }
  87.     close(ss);
  88.     
  89.     return 0;
  90. }
2、客户端网络程序client_tcp.c

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<strings.h>
  4. #include<sys/types.h>
  5. #include<sys/socket.h>
  6. #include<unistd.h>
  7. #include<linux/in.h>

  8. #define PORT 8888    //端口

  9. void process_conn_client(int ss)
  10. {
  11.     ssize_t size=0;
  12.     char buffer[1024];
  13.     
  14.     for(;;)
  15.     {
  16.         size=read(0,buffer,sizeof(buffer));
  17.         if(size==0)
  18.         {
  19.             printf("read error\n");
  20.             return;
  21.         }
  22.         write(ss,buffer,size);
  23.         size=read(ss,buffer,sizeof(buffer));
  24.         write(1,buffer,size);
  25.     }
  26. }

  27. int main(int argc,char *argv[])
  28. {
  29.     struct sockaddr_in server_addr;
  30.     int err;
  31.     int ss;
  32.     
  33.     //创建流式套接字
  34.     ss=socket(AF_INET,SOCK_STREAM,0);
  35.     if(ss<0)
  36.     {
  37.         printf("creat socket error\n");
  38.         return -1;
  39.     }
  40.     
  41.     //设置服务器地址
  42.     bzero(&server_addr,sizeof(server_addr));
  43.     server_addr.sin_family=AF_INET;
  44.     server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
  45.     server_addr.sin_port=htons(PORT);
  46.     inet_pton(AF_INET,argv[1],&server_addr.sin_addr);
  47.     
  48.     //连接服务器
  49.     connect(ss,(struct sockaddr *)&server_addr,sizeof(struct sockaddr));
  50.     process_conn_client(ss);
  51.     close(ss);//关闭连接

  52.     return 0;
  53. }

五、信号处理
注册信号处理函数
#include
typedef void (sighandler_t)(int);
sighandler_t signal(int signum,sigheadler_t handler);


















































阅读(2015) | 评论(0) | 转发(0) |
1

上一篇:ppp移植

下一篇:没有了

给主人留下些什么吧!~~