您的位置:首页 > 理论基础 > 计算机网络

关于socket应用:一个不断监听一个进程的服务器以及发送信息的客户端 TCP的三次握手和四次挥手

2016-07-16 18:35 951 查看
       大端节序:高位节放在低地址

       小端节序:高位节放在高地址

       PC多采用小端节序,而手机多采用大端节序,在网络传播过程中一律转换成大端节序,所以大端节序也称为网络字节序。

      主要头文件#include <sys/socket.h>

      linux提供了四个函数来完成主机字节序和网络字节序的转换,我常用的是

      #include <netinet/in.h>

       unsigned short int htons(unsigned short int hostshort);

       TCP/IP有sockaddr_in和sockaddr_in6两个专用socket地质结构体,用于IPv4和IPv6,个人常用sockaddr_in

        struct sockaddr_in

        {

              sa_family_t    sin_family;//地址族

              u_int16_t       sin_port;  //端口号

             struct in_addr sin_addr;  //IPv4地址结构体

         } ;

          struct in_addr

         {

            u_int32_t s_addr;     //IPv4地址,要用网络字节序表示

         };

         ||||||||||特别注意的是所有的专用socket地址类型的变量在使用的时候都需要转化为通用socket地址类型sockaddr,因为所有socket编程接口使用的地址参数的类型都是sockaddr.

         

         IP地址转换函数

         对于IPv4,用的是点分十进制字符串表示,但是编程中我们需要先把它们转化为整数(二进制)方能使用.

          #include <arpa/inet.h>

          int_addr_t inet_addr(const char* strptr);//作用是把原先的点分十进制字符串转换成网络字节序表示的IPv4地址.

          (1) 创建socket

            #include <sys/types.h>

            #include <sys/socket.h>

            int socket(int domain,int type,int protocol);

            domain参数告诉系统使用哪个底层协议族AF_INET(OR PF_INET)表示的是IPv4

            type用于指定服务类型,SOCK_STREAM(流服务),SOCK_DGRAM(数据报)服务。取用SOCK_STREAM表示用的是TCP协议,用SOCK_DGRAM则表示用的是UDP服务。

            protocol通常设置为0 

            返回值:成功则返回一个文件描述符,失败就返回-1

           (2)命名socket

             #include <sys/types.h>

             #include <sys/socket.h>

             int bind(int sockfd,const struct sockaddr* my_addr,socklen_t addrlen);

             这个操作客户端一般不用,他将一个socket与socket地址绑定在一起,这样客户端才知道如何连接他。

             bind将my_addr所指的socket地址分配给未命名的sockfd文件描述符

             addrlen指出该socket地址的长度      

              bind成功返回0,失败返回-1.

               

             (3)监听sockfd

              sockfd被命名之后,我们还需要创建一个监听队列来存放待处理的客户连接。

              #include <sys/socket.h>

               int listen(int sockfd,int backlog);

               sockfd指定被监听的sockfd,backlog提示内核监听队列的最大长度。只表示处于完全连接状态的socket的上限

               

              (4)接受连接

                #include <sys/types.h>

                #include <sys/socket.h>

                int accept(int sockfd,struct sockaddr* addr,socklen_t *addrlen);

                addr的作用是用来监听远程地址

                sockfd的作用是执行过listen系统调用的监听socket。

              (5)发起连接

                 #include <sys/types.h>

                 #include <sys/socket.h>

                 int connect(int sockfd,const struct sockaddr* serv_addr,socklen_t addrlen);

                 sockfd,是由系统调用产生的,第二个参数是监听的sockfd地址,addrlen指定地址长度

                 成功0,失败-1                

                    

               (6)关闭连接

                   #include <unistd.h>

                   int close(int fd);

                  每使用一次fd引用计数减一,知道减到0为止。

                  (7)TCP数据读写

                   #include <sys/types.h>

                   #include <sys/socket.h>

                   ssize_t recv(int sockfd,void *buf,size_t len,int flags);

                   ssize_t send(int sockfd,const void* buf,size_t len,int flags);

                   向sockfd上读写数据,最后一个参数一般都是0

     

#include <netinet/in.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <assert.h>

int main(int argc,char *argv[])

{

    int sockfd = socket(AF_INET,SOCK_STREAM,0);

    assert(sockfd!=-1);

    struct sockaddr_in saddr,caddr;

    saddr.sin_family = AF_INET;

    saddr.sin_port = htons(6500);

    saddr.sin_addr.s_addr = inet_addr("192.168.1.11");

    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));

    assert(res!=-1);

    listen(sockfd,5);

    int len = sizeof(caddr);

    int c = accept(sockfd,(struct sockaddr*)&caddr,&len);

    while(1)

    {

         if(c<0)

         {

              continue;

         }

         char buff[128] = {0};

         recv(c,buff,127,0);

         printf("%s",buff);

    }

    close(c);

    return 0;

}

              

客户端                                    

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

#include <unistd.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

int main(int argc,char *argv[])

{

   int sockfd = socket(AF_INET,SOCK_STREAM,0);

   assert(sockfd!=-1);

   struct sockaddr_in saddr;//虽然操作一样,但是客户端是为了去链接服务端

   memset(&saddr,0,sizeof(saddr));

   saddr.sin_family = AF_INET;

   saddr.sin_port = htons(6500);//转换成大端

   saddr.sin_addr.s_addr = inet_addr("192.168.1.11");

 //要用就必须先运行起来

   int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//链接到服务端上面

   assert(res!=-1);

   //执行到这个地方说明三次握手完成

   while(1)

   {

       printf("input:\n");

       char buff[128] = {0};

       fgets(buff,128,stdin);//fgets会用到空格回车

       if(strncmp(buff,"end",3)==0)

       {

           break;

       }

       send(sockfd,buff,strlen(buff),0);//把收到的讯息再发送出去

       memset(buff,0,128);

   }

   close(sockfd);//关闭

   return 0;

}

ACK : TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1

SYN(SYNchronization) : 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此,  SYN置1就表示这是一个连接请求或连接接受报文。

FIN (finis)即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。

TCP三次握手四次挥手中三种报文的作用

首先由Client发出请求连接即 SYN=1 ACK=0  (请看头字段的介绍), TCP规定SYN=1时不能携带数据,但要消耗一个序号,因此声明自己的序号是 seq=x

然后 Server 进行回复确认,即 SYN=1 ACK=1 seq=y, ack=x+1,
(为什么在连接的时候服务器端在接收到了客户端的SYN后返回的时候返回的是SYN=1 ACK=1...)的原因

作为补充
http://blog.csdn.net/oney139/article/details/8103223
这位前辈写的很详细,我做个记录方便以后复习
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: