Chinaunix首页 | 论坛 | 博客
  • 博客访问: 211762
  • 博文数量: 58
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 11
  • 用 户 组: 普通用户
  • 注册时间: 2014-09-02 01:08
文章分类
文章存档

2020年(1)

2018年(2)

2017年(1)

2016年(7)

2015年(31)

2014年(16)

我的朋友

分类: C/C++

2015-08-09 18:01:03

一:引子
      在网络五层中:数据链路层-----------------------------------MAC地址
                               网际层----------------------------------------IP地址
                               传输层----------------------------------------IP地址:端口号
二:端口
     有了网络地址,就可以唯一标识网络上的每台计算机,但是在一台计算机上面可以同时运行多个程序,而他们可能同时要访问网络,对于一台计算机上的多个应用程 序,TCP 和 UDP协议采用了16位的端口号来标识他们。一台主机上的不同进程可以绑定到不同的端口上,这些进程都可以访问网络而互不干扰。
  0---------1023           知名端口     由权威机构规定其用途
  1024-----65535        自由端
三:相关数据结构
1、套接字地址结构 struct sockaddr{  unsigned short sa_family; char sa_data[14];};
     sa_family : 表示套接字的协议类型,对应于TCP/IP协议该值为 AF_INET;
     sa_data    : 用于存储具体的协议地址,他等价于一个数据结构:sockadd_in
2、TCP/IP地址协议族格式:struct sockaddr_in { unsigned short sin_family; unsigned short int  sin_port; struct
      in_addr sin_addr ; unsigned char  sin_zero[8]; };
      sin_family: 表示地址类型,对于使用TCP/IP协议进行的网络编程,该值只能为AF_INET。
      sin_port   : 表示端口号
      sin_addr  : 用于存储32位的IP地址
      sin_zero  : 该数组作为填充字段,一般赋值为0
3、struct in_addr {unsigned long s_addr};
四、调用函数
I :创建套接字  int socket (int domain, int type , int protocol)
      --------domain用于指定创建套接字所使用的协议族。
          AF_UNIX # 创建只在本机进行通信的套接字;
          AF_INET # 使用IPv4TCP/IP协议;
          AF_INET6 # 使用IPv6TCP/IP协议
     ---------type用于指定套接字的类型。
          SOCK_STREAM # 创建TCP流套接字;
          SOCK_DGRAM # 创建DUP套接字;
          SOCK_RAW      # 创建原始套接字;
    ----------protocol通常设定为0,表示通过参数domain指定的协议族和参数type指定的套接字类型来确定使用的协议。
II:建立连接 int connect (int sockfd, const struct sockaddr * serv_addr,socklen_t addrlen)
    ---------sockfd是由一个函数socket创建的套接字
    --------- addrlen是serv_addr的长度
III:绑定套接字 int bind (int sockfd , struct sockaddr * my_addr, socklen_t addrlen)
     --------对于只有一个IP地址的计算机表示本机的IP地址,对于有多个IP地址则表示本服务程序将处理来自所有网
                络接口上相应端口的连接请求。
IV:在套接字上创建监听 int listen(int s, int len)
     ---------通过函数socket()创建的字是主动套接字,这种套接字可以用来主动请求链接到某个服务器,但是作为服
                 务器端的程序,通常在某个端口上监听等待来自客户端的连接请求。
     ---------通过listen将该套接字转换为监听套接字,等待来自于客户端的连接请求。一般多个客户可以连接到一个服务器上,服务器向这些客户端提供某种服务,服务器端设置一个连接队列,记录已经建立的连接,参数len指定了该连接队列的最大长度。
IIV:接受连接 int accept(int s, struct sockaddr *addr , socklen_t *addrlen)
     ---------s 是由函数socket创建,经过函数bind绑定的到本地某一个端口上,然后通过函数listen转换而来的监听套
                 接字
     ---------addr 用来保存发起连接请求的主机的地址和端口
     ---------addrlen 是参数addr所指向的结构体的大小
IIIV:ssize_t   send(int s, const void *msg, size_t len , int flags)
     -------------s是已经建立好的套接字描述符
     -------------flags是控制选项
                     MSG_OOB               # 在指定的套接字上发送带外数据,该类型的套接字必须支持带外数据
                     MSG_DONTROUTE  #  通过最直接的路径发送数据,而忽略下层协议的路由设置
         ssize_t   recv(int socked,const void *msg, size_t len , int flags)
     -------------flags是控制选项
                     MSG_OOB               # 请求接收带外数据
                     MSG_PEEK               # 查看数据而不读出
                     MSG_WAITALL        # 只在接收缓冲区满时才返回
四:C/S 结构模型图
五:程序实例

server.c

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<sys/types.h>
  4. #include<sys/socket.h>
  5. #include<string.h>
  6. #include<unistd.h>
  7. #include<netinet/in.h>
  8. #include<arpa/inet.h>

  9. #define USERNAME 0
  10. #define USERPASS 1
  11. #define PORT_SERV 4055
  12. #define LISTENL 12
  13. #define BUFSIZE 1024
  14. struct userinfo{
  15. char username[32];
  16. char userpass[32];
  17. };
  18. typedef struct userinfo userinfo_c;
  19. userinfo_c users[]={{"linux","unix"},{"787","007"},{"gyeve","gaoyi"}};
  20. int send_data(int con,char *buf)
  21. {
  22.     int ret;
  23.     ret=send(con,buf,sizeof(buf),0);
  24.     if(ret<=0){
  25.         printf("send is wrong\n");
  26.     return ret;
  27.     }
  28.     return ret;
  29. }
  30. int find_name(char *name)
  31. {
  32.     int index=0;
  33.     for(index=0;index<3;index++)
  34.     {
  35.     printf("name = %s username = %s\n",name,users[index].username);
  36.         if(strcmp(users[index].username,name)==0)
  37.             return index;
  38.     }
  39.     return -1;
  40. }
  41. int main()
  42. {
  43.     int socket_id,optval,user_id,accpt_len;
  44.     struct sockaddr_in server_ad,client_ad;
  45.     int acc_res, ret,flag=USERNAME;
  46.     pid_t pid;
  47.     char buf[BUFSIZE];

  48.     socket_id = socket(AF_INET,SOCK_STREAM,0);
  49.     if(socket_id <=0) {
  50.      perror("socket");
  51.      exit(1);
  52.     }
  53.     optval=1;
  54.     if(setsockopt(socket_id,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int))<0){/*设置窗口重新绑定*/
  55.     perror("setsockopt");
  56.     exit(2);
  57.     }
  58.     memset(&server_ad,0,sizeof(struct sockaddr_in));
  59.     server_ad.sin_family = AF_INET; /*ipv4 of the tcp/ip protocol */
  60.     server_ad.sin_port = htons(PORT_SERV);
  61.     server_ad.sin_addr.s_addr = htonl(INADDR_ANY);/* the localhost ip address */

  62.     if(bind(socket_id,(struct sockaddr *)&server_ad,sizeof(struct sockaddr_in))<0)
  63.     {
  64.     perror("bind");
  65.     exit(3);
  66.     }
  67.     if(listen(socket_id,LISTENL)<0)
  68.     {
  69.     perror("listen");
  70.     exit(4);
  71.     }
  72.     accpt_len= sizeof(struct sockaddr_in);
  73.     while(1)
  74.     {
  75.     acc_res = accept(socket_id,(struct sockaddr *)&client_ad,&accpt_len);
  76.     if(acc_res <0)
  77.     {
  78.     perror("1accept");
  79.     exit(5);
  80.     }
  81.     printf("accept a new client ,the ip = %s\n",inet_ntoa(client_ad.sin_addr));
  82.     if((pid=fork())==0){
  83.         while(1){
  84.         memset(buf,0,BUFSIZE);
  85.         if((ret=recv(acc_res,buf,BUFSIZE,0))<0){
  86.         perror("recv");
  87.         exit(7);
  88.         }
  89.         buf[ret]=0;
  90.         printf("buf = %s\n",buf);
  91.         if(flag==USERNAME){
  92.             user_id=find_name(buf);
  93.             switch(user_id)
  94.             {
  95.                 case -1:send_data(acc_res,"n\n");
  96.                 break;
  97.                 default:send_data(acc_res,"y\n");
  98.                 flag = USERPASS;
  99.             }
  100.         }
  101.         else if( flag==USERPASS ){
  102.             if(strcmp(users[user_id].userpass,buf)==0)
  103.             {
  104.                 send_data(acc_res,"y\n");
  105.                 send_data(acc_res,"welcome login my cp server\n");
  106.                 printf("%s login\n",users[user_id].username);
  107.                 break;
  108.             }else
  109.                 send_data(acc_res,"n\n");
  110.         }
  111.         }
  112.         
  113.         close(socket_id);
  114.         close(acc_res);
  115.         exit(0);
  116.         }
  117.     else
  118.         close(acc_res);
  119.     }
  120.     return 0;
  121. }

client.c

  1. #include<stdio.h>
  2. #include<arpa/inet.h>
  3. #include<netinet/in.h>
  4. #include<sys/types.h>
  5. #include<sys/socket.h>
  6. #include<stdlib.h>
  7. #include<string.h>
  8. #define LEN 1024
  9. #define VALID 1
  10. #define INVALID 0
  11. int my_recv(int con, char buf[], int len)
  12. {
  13.     int ll;
  14.     ll = recv(con,buf,sizeof(buf),0);
  15.     if(ll<0){
  16.         perror("recv");
  17.         exit(1);
  18.     }
  19.     return ll;
  20. }
  21. void input_mess(int con, const char *string)
  22. {
  23.     char input_buf[32];
  24.     char recv_buf[LEN];
  25.     int flag_userinfo;
  26.     do{
  27.         printf("%s:",string);

  28.         gets(input_buf);
  29.         input_buf[strlen(input_buf)]=0;
  30.         printf("%s:",input_buf);
  31.         if(send(con,input_buf,strlen(input_buf),0)<0)
  32.         {
  33.             perror("send");
  34.             exit(1);
  35.         }
  36.         if(my_recv(con,recv_buf,sizeof(recv_buf))<0)
  37.         {
  38.             perror("my_recv");
  39.             exit(1);
  40.         }
  41.         printf("recv = %s\n",recv_buf);
  42.         if(recv_buf[0]=='y')
  43.             flag_userinfo = VALID;
  44.         else
  45.             flag_userinfo = INVALID;
  46.         memset(recv_buf,0,sizeof(recv_buf));
  47.     }while(flag_userinfo == INVALID);
  48. }
  49. int main(int argc, char *argv[])
  50. {
  51.     int i,ret;
  52.     int conn_fd,socketd;
  53.     char recvbuf[LEN]={0};
  54.     struct sockaddr_in serv_addr;

  55.     if(argc!=5)
  56.     {
  57.         printf("the argc is not equals 5\n");
  58.         return -1;
  59.     }
  60.     memset(recvbuf,0,LEN);
  61.     memset(&serv_addr,0,sizeof(struct sockaddr_in));
  62.     serv_addr.sin_family=AF_INET;
  63.     for(i=0;i<argc;i++)
  64.     {
  65.         if(strcmp(argv[i],"-a")==0)
  66.         {
  67.             i++;
  68.             if(inet_aton(argv[i],&serv_addr.sin_addr)==0){
  69.                 printf("invaild server ip address \n");
  70.                 exit(1);
  71.             }/*如果该for中两个条件的判定是通过两个if链接的,那么要使用continue*/
  72.         }
  73.         else if(strcmp(argv[i],"-p")==0)
  74.         {
  75.             i++;
  76.             int port = atoi(argv[i]);
  77.             if(port<0||port>=65536) {
  78.                 printf("the port is overwiding\n");
  79.                 break;
  80.             }else{
  81.             serv_addr.sin_port = htons(port);
  82.             }
  83.         }
  84.     }
  85.     if(serv_addr.sin_addr.s_addr == 0||serv_addr.sin_port == 0)
  86.     {
  87.         printf("usage [-a] [address] [-p] [port]\n");
  88.         exit(1);
  89.     }
  90.     socketd = socket(AF_INET,SOCK_STREAM,0);
  91.     conn_fd = connect(socketd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr));
  92.     if(conn_fd<0)
  93.     {
  94.         perror("connect");
  95.         exit(1);
  96.     }
  97.     input_mess(socketd,"username");
  98.     input_mess(socketd,"userpass");
  99.     if((ret=my_recv(socketd,recvbuf,LEN))<0)
  100.     {
  101.         printf("data is too long");
  102.         exit(1);
  103.     }
  104. //    recvbuf[ret]=0;
  105.     printf("%s\n",recvbuf);
  106.     

  107.     return 0;
  108. }
六:编写程序遇到的问题

accept: Bad file descriptor---------------将accept创建的套接字在不合适的场合关了
connect: connected refused-------------connect的参数s有问题

            
阅读(1523) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~