网络编程1.0

socket: 

  函数原型:
    int socket(int  domain, int  type, int  protocol);
  网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
 
  domain 协议域,又称协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF_ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
  type 指定Socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的 UDP服务应用。
  protocol 指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
   注意:1.type和protocol不可以随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当第三个参数为0时,会自动选择第二个参数类型对应的默认协议。
     2.WindowsSocket下protocol参数中不存在IPPROTO_STCP。
 
struct sockaddr:
在linux环境下,该结构体在/usr/include/linux/socket.h中定义,具体如下:
  struct sockaddr {
      unsigned short   sa_family;  /* 地址族, AF_xxx */
      char          sa_data[14];  /* 14字节的协议地址*/
  };
 
struct sockaddr_in:
  在linux环境下,结构体struct sockaddr_in在/usr/include/netinet/in.h中定义,具体如下:
  struct sockaddr_in {
  short int      sin_family; /* 地址族 */
  unsigned short   int sin_port; /* 端口号 */
  struct in_addr     sin_addr; /* Internet地址 */
  unsigned char    sin_zero[8]; /* 与struct sockaddr一样的长度 */

  };

inet_pton:将“点分十进制” -> “二进制整数”
int inet_pton(int af, const char *src, void *dst);
这个函数转换字符串到网络地址,第一个参数af是地址簇,第二个参数*src是来源地址,第三个参数* dst接收转换后的数据。
inet_pton 是inet_addr的扩展,支持的多地址族有下列:
af =  AF_INET
src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址转换为 in_addr结构体,并复制在*dst中。
af = AF_INET6
src为指向IPV6的地址,函数将该地址转换为in6_addr的结构体,并复制在*dst中。
如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0。

inet_pton是一个IP地址转换函数,可以在将IP地址在“点分十进制”和“二进制整数”之间转换而且,inet_pton和inet_ntop这2个函数能够处理ipv4和ipv6。

inet_pton函数成功的话返回1,参数无效返回0,错误返回-1;

connect()用于建立与指定socket的连接。
头文件: #include <sys/socket.h>
函数原型: int connect(SOCKET s, const struct sockaddr * name, int namelen);
参数:
s:标识一个未连接socket
name:指向要连接套接字的 sockaddr结构体的指针
namelen:sockaddr结构体的字节长度。
 
 
代码1:(写)
 1 #include"common.h"
 2 
 3 typedef struct stu
 4 {
 5     int id;
 6     char name[20];
 7     struct stu *next;
 8 }Stu,*PStu;
 9 
10 void create_list(PStu *phead) //创建链表函数
11 {
12     *phead=NULL;
13     PStu ptr,r;
14     int id;
15     char name[20];
16     printf("当id为0时结束添加\n");
17     printf("id=");
18     scanf("%d",&id);getchar();
19     while(id>0)
20     {
21         printf("name=");
22         scanf("%s",name);getchar();
23         ptr=malloc(sizeof(Stu));
24         ptr->id=id;
25         strcpy(ptr->name,name);
26         ptr->next=NULL;
27         if(*phead==NULL)
28         {
29             *phead=ptr;
30         }
31         else
32         {
33             r->next=ptr;
34         }
35         r=ptr;
36 
37         printf("当id为0时结束添加\n");
38         printf("id=");
39         scanf("%d",&id);getchar();
40     }
41     return ;
42 }
43 
44 void fun()
45 {
46     printf("链接中断\n");
47     return;
48 }
49 
50 int main()
51 {
52     int fd;
53     int ret;
54     struct sockaddr_in saddr;
55     signal(SIGPIPE,fun);//捕捉信号
56     fd=socket(AF_INET,SOCK_STREAM,0);
57     if(fd<0)
58     {
59         perror("socket");
60         return -1;
61     }
62     saddr.sin_family=AF_INET;
63     saddr.sin_port=htons(9000);
64     inet_pton(AF_INET,"192.168.6.128",&saddr.sin_addr.s_addr);//本机IP
65     ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));
66     if(ret<0)
67     {
68         perror("connect");
69         goto END;
70     }
71 
72     PStu head=NULL;//发送链表
73     create_list(&head);
74     PStu p=head;
75     for(;p!=NULL;p=p->next)
76     {
77         ret = write(fd,p,sizeof(Stu));
78         if(ret<0)
79         {
80             perror("write");
81         }
82     }
83 END:
84     close(fd);
85     return 0;
86 }

bind:

  将一本地地址与一套接口捆绑。本函数适用于未连接的数据报或流类套接口,在connect()listen()调用前使用。当用socket()创建套接口后,它便存在于一个名字空间(地址族)中,但并未赋名。bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)。

如无错误发生,则bind()返回0。否则的话,将返回-1,应用程序可通过WSAGetLastError()获取相应 错误代码

错误代码

编辑
WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。
WSAENETDOWN: 套接口实现检测到网络子系统失效。
WSAEADDRINUSE:所定端口已在使用中(参见setoption()中的SO_REUSEADDR选项)。
WSAEFAULT:namelen参数太小(小于sockaddr结构的大小)。
WSAEINPROGRESS:一个阻塞的套接口调用正在运行中。
WSAEAFNOSUPPORT:本协议不支持所指定的地址族。
WSAEINVAL:该 套接口已与一个地址捆绑。
WSAENOBUFS:无足够可用缓冲区,连接过多。
WSAENOTSOCK:描述字不是一个套接口。
 
listen:
  为了接受连接,先用socket()创建一个套接口的描述字,然后用listen()创建套接口并为申请进入的连接建立一个后备日志,然后便可用accept()接受连接了。
int listen( int sockfd, int backlog);
  sockfd:用于标识一个已捆绑未连接套接口的描述字。
  backlog:等待连接队列的最大长度。
如无错误发生,listen()返回0。否则的话,返回-1,应用程序可通过WSAGetLastError()获取相应 错误代码

错误代码

编辑
WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。
WSAENETDOWN: 套接口实现检测到网络子系统失效。
WSAEADDRINUSE:试图用listen()去监听一个正在使用中的地址。
WSAEINPROGRESS:一个阻塞的套接口调用正在运行中。
WSAEINVAL:该套接口未用 bind()进行捆绑,或已被连接。
WSAEISCONN:套接口已被连接。
WSAEMFILE:无可用文件描述字。
WSAENOBUFS:无可用缓冲区空间。
WSAENOTSOCK:描述字不是一个 套接口
WSAEOPNOTSUPP:该套接口不正常listen()调用。
 
 
代码2:(读、打印)
  1 #include "common.h"
  2 typedef struct stu
  3 {
  4     int id;
  5     char name[20];
  6     struct stu *next;
  7 }Stu,*PStu;
  8 
  9 void fun(int sig)
 10 {
 11     printf("recv pip:%d\n",sig);
 12     return;
 13 }
 14 
 15 void show(PStu head)
 16 {
 17     printf("学号\t姓名\n");
 18     while(head!=NULL)
 19     {
 20         printf("%d\t%s\n",head->id,head->name);
 21         head=head->next;
 22     }
 23     return ;
 24 }
 25 
 26 int main()
 27 {
 28     PStu head=NULL;
 29     Stu *ptr;
 30     PStu r;
 31     int fd,nfd;
 32     int ret;
 33     struct sockaddr_in  saddr,caddr;
 34     int addr_len;
 35     signal(SIGPIPE,fun);
 36 
 37     fd = socket(AF_INET,SOCK_STREAM,0);
 38     if(fd<0)
 39     {
 40         perror("socket");
 41         return -1;
 42     }
 43 
 44     saddr.sin_family = AF_INET;
 45     saddr.sin_port   = htons(9000);
 46     inet_pton(AF_INET,"192.168.6.128",&saddr.sin_addr.s_addr);//本机IP
 47 
 48     ret = bind(fd,(struct sockaddr*)&saddr,sizeof(saddr));
 49     if(ret<0)
 50     {
 51         perror("bind");
 52         goto END;
 53     }
 54 
 55     ret = listen(fd,20);
 56     if(ret<0)
 57     {
 58         perror("listen");
 59         goto END;
 60     }
 61 
 62     addr_len = sizeof(caddr);
 63     printf("accept..\n");
 64     nfd = accept(fd,(struct sockaddr*)&caddr,&addr_len);
 65     printf("accept over..\n");
 66     if(nfd<0)
 67     {
 68         perror("accept");
 69     }
 70     printf("read...\n");
 71     while(1)
 72     {
 73         ptr=malloc(sizeof(Stu));
 74         ret=read(nfd,ptr,sizeof(Stu));
 75         if(ret<0)
 76         {
 77             perror("read");break;
 78         }
 79         if(ret==0)
 80         {
 81 
 82             printf("read over\n");
 83             show(head);
 84             break;
 85         }
 86         if(ret>0);
 87         {
 88             ptr->next=NULL;
 89             if(head==NULL)
 90             {
 91                 head=ptr;
 92             }
 93             else
 94             {
 95                 r->next=ptr;
 96             }
 97             r=ptr;
 98         }
 99     }
100     101     102 
103     close(nfd);
104 
105 END:
106     close(fd);
107     return 0;
108 }

 运行结果试行:

猜你喜欢

转载自www.cnblogs.com/it8343/p/9261217.html