Socket means "socket", which is a convention for communication between computers, and can also be regarded as a technology. Through the socket convention, a computer can receive data from other computers, and can also send data to other computers.
The bottom layer in the socket is:
typedef __uint32_t in_addr_t; /* base type for internet address */
Then it is put into a structure called in_addr for later use.
/*
* Internet address (a structure for historical reasons)
*/
struct in_addr {
in_addr_t s_addr;
};
Then it is put into the structure of sockaddr_in, that is, the socket address, which is the internet method.
/*
* Socket address, internet style.
*/
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
The socket address is defined again in the socket.h file, which includes its length, address family, and address value.
struct sockaddr {
__uint8_t sa_len; /* total length */
sa_family_t sa_family; /* [XSI] address family */
char sa_data[14]; /* [XSI] addr value (actually larger) */
};
So let's take a look at the address family.
/*
* Address families.
*/
#define AF_UNSPEC 0 /* unspecified */
#define AF_UNIX 1 /* local to host (pipes) */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define AF_LOCAL AF_UNIX /* backward compatibility */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define AF_IMPLINK 3 /* arpanet imp addresses */
#define AF_PUP 4 /* pup protocols: e.g. BSP */
#define AF_CHAOS 5 /* mit CHAOS protocols */
#define AF_NS 6 /* XEROX NS protocols */
#define AF_ISO 7 /* ISO protocols */
#define AF_OSI AF_ISO
#define AF_ECMA 8 /* European computer manufacturers */
#define AF_DATAKIT 9 /* datakit protocols */
#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
#define AF_SNA 11 /* IBM SNA */
#define AF_DECnet 12 /* DECnet */
#define AF_DLI 13 /* DEC Direct data link interface */
#define AF_LAT 14 /* LAT */
#define AF_HYLINK 15 /* NSC Hyperchannel */
#define AF_APPLETALK 16 /* Apple Talk */
#define AF_ROUTE 17 /* Internal Routing Protocol */
#define AF_LINK 18 /* Link layer interface */
#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
#define AF_COIP 20 /* connection-oriented IP, aka ST II */
#define AF_CNT 21 /* Computer Network Technology */
#define pseudo_AF_RTIP 22 /* Help Identify RTIP packets */
#define AF_IPX 23 /* Novell Internet Protocol */
#define AF_SIP 24 /* Simple Internet Protocol */
#define pseudo_AF_PIP 25 /* Help Identify PIP packets */
/*define pseudo_AF_BLUE 26 Identify packets for Blue Box - Not used */
#define AF_NDRV 27 /* Network Driver 'raw' access */
#define AF_ISDN 28 /* Integrated Services Digital Network*/
#define AF_E164 AF_ISDN /* CCITT E.164 recommendation */
#define pseudo_AF_KEY 29 /* Internal key-management function */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define AF_INET6 30 /* IPv6 */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define AF_NATM 31 /* native ATM access */
#define AF_SYSTEM 32 /* Kernel event messages */
#define AF_NETBIOS 33 /* NetBIOS */
#define AF_PPP 34 /* PPP communication protocol */
#define pseudo_AF_HDRCMPLT 35 /* Used by BPF to not rewrite headers
* in interface output routine */
#define AF_RESERVED_36 36 /* Reserved for internal usage */
#define AF_IEEE80211 37 /* IEEE 802.11 protocol */
#define AF_UTUN 38
#define AF_MAX 40
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
This includes the commonly used AF_INET, including TCP, UDP and other address families.
As for the protocol family, it is currently the same as the address family.
/*
* Protocol families, same as address families for now.
*/
#define PF_UNSPEC AF_UNSPEC
#define PF_LOCAL AF_LOCAL
#define PF_UNIX PF_LOCAL /* backward compatibility */
#define PF_INET AF_INET
#define PF_IMPLINK AF_IMPLINK
#define PF_PUP AF_PUP
#define PF_CHAOS AF_CHAOS
#define PF_NS AF_NS
#define PF_ISO AF_ISO
#define PF_OSI AF_ISO
#define PF_ECMA AF_ECMA
#define PF_DATAKIT AF_DATAKIT
#define PF_CCITT AF_CCITT
#define PF_SNA AF_SNA
#define PF_DECnet AF_DECnet
#define PF_DLI AF_DLI
#define PF_LAT AF_LAT
#define PF_HYLINK AF_HYLINK
#define PF_APPLETALK AF_APPLETALK
#define PF_ROUTE AF_ROUTE
#define PF_LINK AF_LINK
#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */
#define PF_COIP AF_COIP
#define PF_CNT AF_CNT
#define PF_SIP AF_SIP
#define PF_IPX AF_IPX /* same format as AF_NS */
#define PF_RTIP pseudo_AF_RTIP /* same format as AF_INET */
#define PF_PIP pseudo_AF_PIP
#define PF_NDRV AF_NDRV
#define PF_ISDN AF_ISDN
#define PF_KEY pseudo_AF_KEY
#define PF_INET6 AF_INET6
#define PF_NATM AF_NATM
#define PF_SYSTEM AF_SYSTEM
#define PF_NETBIOS AF_NETBIOS
#define PF_PPP AF_PPP
#define PF_RESERVED_36 AF_RESERVED_36
#define PF_UTUN AF_UTUN
#define PF_MAX AF_MAX
The following are the types of Socket, the most common are sock_stream and sock_dgram, which are the data transmission methods of TCP and UDP respectively
/*
* Types
*/
#define SOCK_STREAM 1 /* stream socket */
#define SOCK_DGRAM 2 /* datagram socket */
#define SOCK_RAW 3 /* raw-protocol interface */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define SOCK_RDM 4 /* reliably-delivered message */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define SOCK_SEQPACKET 5 /* sequenced packet stream */
SOCK_STREAM
represents a connection-oriented data transfer method. Data arrives at another computer without error, and can be resent if damaged or lost, but relatively slowly. The common http protocol uses SOCK_STREAM to transmit data, because it is necessary to ensure the correctness of the data, otherwise the web page cannot be parsed normally.SOCK_DGRAM
represents a connectionless data transfer method. The computer only transmits the data without checking the data. If the data is damaged during transmission, or does not reach another computer, there is no way to remedy it. That is to say, if the data is wrong, it is wrong and cannot be retransmitted. Because SOCK_DGRAM does less verification work, it is more efficient than SOCK_STREAM.
The difference between TCP and UDP is as follows:
TCP is connection-oriented. The processes on both sides of the interaction each establish a stream socket, and the server needs to wait for the client to submit a connection application to it. A new socket descriptor is returned as soon as the client request is accepted. The data transfer function is called through the descriptor to send and receive data with the client.
UDP is connectionless. The two sides establish a datagram socket. The server and client do not need to apply for and establish a connection before transmitting data, and can send messages to each other at any time.
protocol | TCP | UDP |
---|---|---|
data transmission method | streaming | Datagram |
advantage | reliable and stable | Faster and slightly more secure than TCP |
shortcoming | Slow speed, low efficiency, high system resource occupation, easy to be attacked | unreliable, unstable |
suitable for the scene | High requirements for network communication quality (reliable and stable) | The quality of network communication is not high and the speed is fast. |
It is necessary to distinguish the difference between protocols, services and ports:
services generally correspond to ports, for example, Web services correspond to port 80, FTP services correspond to port 21, and SMTP services correspond to port
25. Protocols refer to protocols such as TCP. The protocol is used in the service. For example, the FTP protocol is used in FTP.
Here is the code on the server side:
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <zconf.h>
int UDP()
{
int server_sockfd;
ssize_t len;
struct sockaddr_in my_addr; //服务器网络地址结构体
struct sockaddr_in remote_addr; //客户端网络地址结构体
socklen_t sin_size;
char buf[BUFSIZ]; //数据传送的缓冲区
memset(&my_addr, 0, sizeof(my_addr)); //数据初始化--清零
my_addr.sin_family = AF_INET; //设置为IP通信
my_addr.sin_addr.s_addr = INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
my_addr.sin_port = htons(8000); //服务器端口号
/*创建服务器端套接字--IPv4协议,面向无连接通信,UDP协议*/
if((server_sockfd = socket(PF_INET, SOCK_DGRAM, 0))<0)
{
perror("socket error");
return 1;
}
/*将套接字绑定到服务器的网络地址上*/
if (bind(server_sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) < 0)
{
perror("bind error");
return 1;
}
printf("my address %s\n", inet_ntoa(my_addr.sin_addr));
sin_size = sizeof(struct sockaddr_in);
printf("waiting for a packet...\n");
/*接收客户端的数据并将其发送给客户端--recvfrom是无连接的*/
if((len = recvfrom(server_sockfd, buf, BUFSIZ, 0, (struct sockaddr *)&remote_addr, &sin_size)) < 0)
{
perror("recvfrom error");
return 1;
}
printf("received packet from %s:\n", inet_ntoa(remote_addr.sin_addr));
buf[len] = '\0';
printf("contents: %s\n", buf);
/*关闭套接字*/
close(server_sockfd);
return 0;
}
int TCP()
{
int server_sockfd;//服务器端套接字
int client_sockfd;//客户端套接字
ssize_t len;
struct sockaddr_in my_addr; //服务器网络地址结构体
struct sockaddr_in remote_addr; //客户端网络地址结构体
socklen_t sin_size;
char buf[BUFSIZ]; //数据传送的缓冲区
memset(&my_addr, 0, sizeof(my_addr)); //数据初始化--清零
my_addr.sin_family = AF_INET; //设置为IP通信
my_addr.sin_addr.s_addr = INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
my_addr.sin_port = htons(8000); //服务器端口号
/*创建服务器端套接字--IPv4协议,面向连接通信,TCP协议*/
if((server_sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error");
return 1;
}
/*将套接字绑定到服务器的网络地址上*/
if(bind(server_sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) < 0)
{
perror("bind error");
return 1;
}
printf("my address %s\n", inet_ntoa(my_addr.sin_addr));
/*监听连接请求--监听队列长度为5*/
if(listen(server_sockfd, 5) < 0)
{
perror("listen error");
return 1;
};
sin_size = sizeof(struct sockaddr_in);
/*等待客户端连接请求到达*/
if((client_sockfd = accept(server_sockfd, (struct sockaddr *)&remote_addr, &sin_size))<0)
{
perror("accept error");
return 1;
}
printf("accept client %s\n", inet_ntoa(remote_addr.sin_addr));
len = send(client_sockfd, "Welcome to my server\n", 21, 0);//发送欢迎信息
/*接收客户端的数据并将其发送给客户端--recv返回接收到的字节数,send返回发送的字节数*/
while((len = recv(client_sockfd, buf, BUFSIZ, 0)) > 0)
{
buf[len] = '\0';
printf("%s\n", buf);
if(send(client_sockfd, buf, len, 0) < 0)
{
perror("write error");
return 1;
}
}
/*关闭套接字*/
close(client_sockfd);
close(server_sockfd);
return 0;
}
int main(int argc, char *argv[])
{
UDP();
return 0;
}
Here is the code for the client:
#include <cstdio>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <zconf.h>
int UDP()
{
int client_sockfd;
ssize_t len;
struct sockaddr_in remote_addr; //服务器端网络地址结构体
socklen_t sin_size;
char buf[BUFSIZ]; //数据传送的缓冲区
memset(&remote_addr, 0, sizeof(remote_addr)); //数据初始化--清零
remote_addr.sin_family = AF_INET; //设置为IP通信
remote_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器IP地址
remote_addr.sin_port = htons(8000); //服务器端口号
/*创建客户端套接字--IPv4协议,面向无连接通信,UDP协议*/
if((client_sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket error");
return 1;
}
strcpy(buf,"This is a test message!"); // 发送的内容
printf("sending: '%s'\n",buf);
sin_size = sizeof(struct sockaddr_in);
/*向服务器发送数据包*/
if((len = sendto(client_sockfd, buf, strlen(buf), 0, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr))) < 0)
{
perror("recvfrom");
return 1;
}
/*关闭套接字*/
close(client_sockfd);
return 0;
}
int TCP()
{
int client_sockfd;
ssize_t len;
struct sockaddr_in remote_addr; //服务器端网络地址结构体
char buf[BUFSIZ]; //数据传送的缓冲区
memset(&remote_addr, 0, sizeof(remote_addr)); //数据初始化--清零
remote_addr.sin_family = AF_INET; //设置为IP通信
remote_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器IP地址
remote_addr.sin_port = htons(8000); //服务器端口号
/*创建客户端套接字--IPv4协议,面向连接通信,TCP协议*/
if((client_sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error");
return 1;
}
/*将套接字绑定到服务器的网络地址上*/
if(connect(client_sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) < 0)
{
perror("Connect error");
return 1;
}
printf("connected to server\n");
len = recv(client_sockfd, buf, BUFSIZ, 0);//接收服务器端信息
buf[len] = '\0';
printf("%s", buf); //打印服务器端信息
/*循环的发送接收信息并打印接收信息(可以按需发送)--recv返回接收到的字节数,send返回发送的字节数*/
while(1)
{
printf("Enter string to send:");
scanf("%s", buf);
if(!strcmp(buf, "quit"))
break;
len = send(client_sockfd, buf, strlen(buf), 0);
len = recv(client_sockfd, buf, BUFSIZ, 0);
buf[len] = '\0';
printf("received:%s\n", buf);
}
/*关闭套接字*/
close(client_sockfd);
return 0;
}
int main(int argc, char *argv[]){
UDP();
return 0;
}