socket知识点整理

在UNIX系统中,一切都是文件,一个int值代表着一个可以打开的文件,这个文件可以执行read()或者write()方法。

四种socket

  • stream socket 使用tcp协议,没有边界大小限制
  • datagram sockets 无连接,使用udp,发一个收一个
  • raw sockets 允许用户接触到底层协议,一般是给那些想开发自己新的协议的人用的
  • sequenced packet sockets 类似于第一种,不过是有大小限制的

IP地址

An IP address is a 32-bit quantity interpreted as four 8-bit numbers or octets. Each IP address uniquely identifies the participating user network, the host on the network, and the class of the user network.An IP address is a 32-bit quantity interpreted as four 8-bit numbers or octets. Each IP address uniquely identifies the participating user network, the host on the network, and the class of the user network.

DNS

These systems are called Domain Name Systems (DNS), which keep the mapping of IP addresses and the corresponding ordinary names.These systems are called Domain Name Systems (DNS), which keep the mapping of IP addresses and the corresponding ordinary names.

2-tier and 3-tier architectures

  • 2-tier architecture − In this architecture, the client directly interacts with the server. This type of architecture may have some security holes and performance problems. Internet Explorer and Web Server work on two-tier architecture. Here security problems are resolved using Secure Socket Layer (SSL).

  • 3-tier architectures − In this architecture, one more software sits in between the client and the server. This middle software is called ‘middleware’. Middleware are used to perform all the security checks and load balancing in case of heavy load. A middleware takes all requests from the client and after performing the required authentication, it passes that request to the server. Then the server does the required processing and sends the response back to the middleware and finally the middleware passes this response back to the client. If you want to implement a 3-tier architecture, then you can keep any middleware like Web Logic or WebSphere software in between your Web Server and Web Browser.

也就是说有两端通信和三端通信两种。其中二端的会有安全隐患,常用SSL来解决。三端的还包括一个中间件,用来处理负载和做安全措施。

Types of Server

There are two types of servers you can have −

  • Iterative Server − This is the simplest form of server where a server process serves one client and after completing the first request, it takes request from another client. Meanwhile, another client keeps waiting.

  • Concurrent Servers − This type of server runs multiple concurrent processes to serve many requests at a time because one process may take longer and another client cannot wait for so long. The simplest way to write a concurrent server under Unix is to fork a child process to handle each client separately.

也就是单线程服务器和多线程服务器。

结构

包括几种不同的数据结构。

struct sockaddr {
   unsigned short   sa_family;
   char             sa_data[14];
};
struct sockaddr_in {
   short int            sin_family;
   unsigned short int   sin_port;
   struct in_addr       sin_addr;
   unsigned char        sin_zero[8];
};
struct in_addr {
   unsigned long s_addr;
};
struct hostent {
   char *h_name; 
   char **h_aliases; 
   int h_addrtype;  
   int h_length;    
   char **h_addr_list

#define h_addr  h_addr_list[0]
};
struct servent {
   char  *s_name; 
   char  **s_aliases; 
   int   s_port;  
   char  *s_proto;
};

其中sa_family包括了常见的AF_INET,代表着ipv4,当然ipv6就是AF_INET6了。
hostent中的h_name代表网址,h_addrtype为AF_INET,对于Internet来说h_length为4。
通常来说,我们都是把以上结构体的指针传给系统并创建一个socket,第二个参数一般是这个结构体的长度。

端口

For our purpose, a port will be defined as an integer number between 1024 and 65535. This is because all port numbers smaller than 1024 are considered well-known – for example, telnet uses port 23, http uses 80, ftp uses 21, and so on.

大端和小端

Little Endian − In this scheme, low-order byte is stored on the starting address (A) and high-order byte is stored on the next address (A + 1).
Big Endian − In this scheme, high-order byte is stored on the starting address (A) and low-order byte is stored on the next address (A + 1).

  • 小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
  • 大端模式 :符号位的判定固定为第一个字节,容易判断正负。
    数组在大端小端情况下的存储:
      以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:
      Big-Endian: 低地址存放高位,如下:

    ---------------
    buf[3] (0x78) -- 低位
    buf[2] (0x56)
    buf[1] (0x34)
    buf[0] (0x12) -- 高位
    ---------------
    低地址
    

    Little-Endian: 低地址存放低位,如下:

    ---------------
    buf[3] (0x12) -- 高位
    buf[2] (0x34)
    buf[1] (0x56)
    buf[0] (0x78) -- 低位
    --------------
    

可以编写一个小的测试程序来判断机器的字节序:

BOOL IsBigEndian()
{
    int a = 0x1234;
    char b =  *(char *)&a;  //通过将int强制类型转换成char单字节,通过判断起始存储位置。即等于 取b等于a的低地址部分
    if( b == 0x12)
    {
        return TRUE;
    }
    return FALSE;
}

如何进行大小端转换

#define BigtoLittle16(A)   (( ((uint16)(A) & 0xff00) >> 8)    | \
                                       (( (uint16)(A) & 0x00ff) << 8))
#define BigtoLittle32(A)   ((( (uint32)(A) & 0xff000000) >> 24) | \
                                       (( (uint32)(A) & 0x00ff0000) >> 8)   | \
                                       (( (uint32)(A) & 0x0000ff00) << 8)   | \
                                       (( (uint32)(A) & 0x000000ff) << 24))

在socket编程中,有以下方法可以直接转换

#define ntohs(n)     //Host to Network ShortHost to Network Short
#define htons(n)     //Network to Host ShortNetwork to Host Short
#define ntohl(n)      //32位数据类型网络字节顺序到主机字节顺序的转换
#define htonl(n)      //32位数据类型主机字节顺序到网络字节顺序的转换

与ip地址相关的函数

把一个点分隔的char数组转换成网络流(小端模式)的ip地址

#include <arpa/inet.h>

(...)

   struct sockaddr_in dest;

   memset(&dest, '\0', sizeof(dest));
   dest.sin_addr.s_addr = inet_addr("68.178.157.132");

(...)

与上一个函数相反的作用

#include <arpa/inet.h>

(...)

   char *ip;

   ip = inet_ntoa(dest.sin_addr);

   printf("IP Address is: %s\n",ip);

(...)

核心函数

  • socket()
#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
  • sockfd − It is a socket descriptor returned by the socket function.

  • serv_addr − It is a pointer to struct sockaddr that contains destination IP address and port.

  • addrlen − Set it to sizeof(struct sockaddr).

由于太懒了所以服务器端的bind()listen()这里就不说了。
- send()

The send function is used to send data over stream sockets or CONNECTED datagram sockets. If you want to send data over UNCONNECTED datagram sockets, you must use sendto() function.

  • sockfd − It is a socket descriptor returned by the socket function.

  • msg − It is a pointer to the data you want to send.

  • len − It is the length of the data you want to send (in bytes).

  • flags − It is set to 0.

也就是说UDP那边也可以用这方法,只不过用的是sendto()。
- recv()

int recv(int sockfd, void *buf, int len, unsigned int flags);
  • sendto()
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

这个不用解释了吧,自己看。
- recvfrom()

int recvfrom(int sockfd, void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen);

同上,udp用的
参考:
https://www.tutorialspoint.com/unix_sockets/index.htm

猜你喜欢

转载自blog.csdn.net/hhh132/article/details/77530583