TCP--server

来源:互联网 发布:如何下载app软件 编辑:程序博客网 时间:2024/06/08 09:37

一个在linux下的基于tcp的服务器和客户端;

具体的网络基础参照谢希仁老师的《计算机网络》来入门;

在TCP/IP协议中,“IP地址+TCP或UDP端⼜号”唯⼀标识⽹
络通讯中的⼀个进程,“IP地址+端⼜号”就称为socket;

先说一些规定吧:

  1. TCP/IP协议规定,⽹络数据流应采⽤⼤端字节序,即低地址⾼字节。
  2. 先发出的数据是低地址,后发出的数据是⾼地址。

所以为了程序的移植性,系统提供了一些接口供我们调用:
hton
其中h表⽰host,n表⽰network,l表⽰32位长整数,s表⽰16位短整数,例 如htonl表⽰将32位的长整数从主机字节序转换为⽹络字节序,例如将IP地址转换后准备发送。

然后我们平时所见到的ip地址一般都是点分式,但是在系统中实际是一个32位的整形,所以系统也为我们提供了一套转换的接口:
把点分式字符串转为in_addr_t:
inet_addr
同时把in_addr_t转回成字符串点分式的:
inet_ntoa

上篇文章中讲过TCP的三次握手和四次挥手了,这次再来看其具体的通信过程及其给用户暴露的接口:

TCP
然后我们再详细谈一下其中的接口的作用:

  1. socket()打开⼀个⽹络通讯端⼜,如果成功的话,就像open()⼀样返回⼀个⽂件描述符,应⽤程序可以像读写⽂件⼀样⽤read/write在⽹络上收发数据,如果socket()调⽤出错则返回-1。对于TCP协议,type参数指定为SOCK_STREAM,表⽰⾯向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表⽰⾯向数据报的传输协 议。第三个参数可以忽略,设为0就好了;
    这里写图片描述

  2. 因为服务器的IP地址和端口号一般都是要固定不变的,所以客户端知道服务器的IP地址就可以访问了,所以服务器要绑定一个固定的IP地址和端口号,所以要用的bind()函数,bind()的作⽤是将参数sockfd和myaddr绑定在⼀起,使sockfd这个⽤于⽹络通讯的⽂件描述符监听myaddr所描述的地址和端⼜号。
    这里写图片描述

  3. 这个时候我们就要监听是不是有客户要来连接我们了,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接等待状态,如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。
    这里写图片描述

  4. 三⽅握⼿完成后,服务器调⽤accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。cliaddr是⼀个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是⼀个传⼊传出参数(value-result argument),传⼊的是调⽤者提供的缓冲区cliaddr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调⽤者提供的缓冲区)。如果给cliaddr 参数传NULL,表⽰不关⼼客户端的地址。
    accept

    这样我们就可以的到客户端的连接了,现在也不做多么复杂的事情,就是把他传来的数据读出来,再给他写回去就好了;

  1 #include <stdio.h>  2 #include <sys/types.h>  3 #include <sys/socket.h>                                                                                                                                               4 #incl  ude <netinet/in.h>  5 #include <arpa/inet.h>  6 #include <stdlib.h>  7   8   9 int main(int argc,char* argv[]) 10 { 11     if(argc != 3)//judge input 12     {               13         printf("tcp/_server + ip + port_number\n"); 14         exit(1); 15     } 16     int sock = socket(AF_INET,SOCK_STREAM,0);//creat socket 17     if(sock < 0) 18     { 19         printf("creat socket error\n"); 20         exit(2); 21     } 22      23     struct sockaddr_in server_socket;//init sockaddr_in 24     struct sockaddr_in client_socket; 25     server_socket.sin_family = AF_INET; 26     server_socket.sin_addr.s_addr = inet_addr(argv[1]); 27     server_socket.sin_port = htons(atoi(argv[2])); 28      29     if(bind(sock,(struct sockaddr*)&server_socket,sizeof(server_socket)) < 0)//bind sock 30     { 31         printf("bind error!\n"); 32         exit(3); 33     } 34  35     if(listen(sock,5) < 0)//listen sock 36     { 37         printf("listen error\n"); 38         exit(4); 39     }                                                                                                                                                                40  41     while(1) 42     { 43         int len = 0; 44         int client_sock = accept(sock,(struct sockaddr*)&client_socket,&len);//accept sock 45         if(client_sock < 0) 46         { 47             printf("accept error!\n"); 48             continue; 49         } 50  51         printf("a new connect from %s   %d\n",inet_ntoa(client_socket.sin_addr),client_socket.sin_port); 52         while(1) 53         {//data processing 54             char buf[1024]; 55             ssize_t s = read(client_sock,buf,sizeof(buf)); 56             if(s>0) 57             { 58                 buf[s] = 0; 59                 printf("client :# %s\n",buf); 60             } 61             else 62             { 63                 printf("read down ..........break;"); 64                 break; 65             } 66             write(client_sock,buf,sizeof(buf)-1); 67         } 68     } 69  70  71     return 0; 72 }                                             

这样一个基本的服务器就写好了,只是最基本的,也只能支持一个人连接而已;
下篇再来讲客户端吧;