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

       大端节序:高位节放在低地址

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

       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

这位前辈写的很详细,我做个记录方便以后复习





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值