目录
30.socket编程
30.1 socket 简介
什么是TCP/IP、UDP?
30.2 socket API
30.2.1 socket编程接口
30.2.2 bind()函数
30.2.3 listen()函数
30.2.4 accept()函数
30.2.5 connect()函数
30.3 TCP Socket编程实例
30.4 UDP Socket编程实例
问题:试描述TCP建立和断开连接时的三次握手和四次挥手
30.socket编程
30.1 socket 简介
套接字(socket)是 Linux 下的一种进程间通信机制(socket IPC),socket 是应用层与 TCP/IP 协议通信的中间软件抽象层,它是一组接口,还是一个标准BSD socket,能在不同平台很方便移植
TCP/IP协议族包括运输层、网络层、链路层,而socket所在位置如图,Socket是应用层与TCP/IP协议族通信的中间软件抽象层。
什么是TCP/IP、UDP?
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
存在于OS中,网络服务通过OS提供,在OS中增加支持TCP/IP的系统调用——Berkeley套接字,如Socket,Connect,Send,Recv等、
是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。如图:
30.2 socket API
30.2.1 socket编程接口
socket()函数类似于 open()函数,它用于创建一个网络通信端点(打开一个网络通信),如果成功则返回一个网络文件描述符,通常把这个文件描述符称为 socket 描述符(socket descriptor)
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//domain: 用于指定一个通信域
//type : 指定套接字的类型
//protocol: 设置为0,表示为给定的通信域和套接字类型选择默认类型
30.2.2 bind()函数
bind()函数用于将一个 IP 地址或端口号与一个套接字进行绑定(将套接字与地址进行关联),(注意这里说的地址包括 IP 地址和端口号),因为对于客户端来说,它与服务器进行通信,首先需要知道服务器的 IP 地址以及对应的端口号,所以通常服务器的 IP 地址以及端口号都是众所周知的
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//最后一个参数addrlen :指定了 addr 所指向的结构体对应的字节长度
参数 addr 是一个指针,指向一个 struct sockaddr 类型变量:
示例代码 30.2.1 struct sockaddr 结构体
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
// 第二个参数sa_data :是一个 char 类型数组,一共 14 个字节,在这 14 个字节中就包括了 IP 地址、端口号等信息
一般我们在使用的时候都会使用 struct sockaddr_in 结构体,sockaddr_in 和 sockaddr 是并列的结构(占用的空间是一样的),指向 sockaddr_in 的结构体的指针也可以指向 sockadd 的结构体,并代替它
示例代码 30.2.2 struct sockaddr_in 结构体
struct sockaddr_in {
sa_family_t sin_family; /* 协议族 */
in_port_t sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP 地址 */
unsigned char sin_zero[8];
};
30.2.3 listen()函数
listen()函数只能在服务器进程中使用,让服务器进程进入监听状态,等待客户端的连接请求,listen()函数在一般在 bind()函数之后调用,在 accept()函数之前调用
int listen(int sockfd, int backlog);
//参数 backlog 用来描述 sockfd 的等待连接队列能够达到的最大值
30.2.4 accept()函数
服务器调用 listen()函数之后,就会进入到监听状态,等待客户端的连接请求,使用 accept()函数获取客户端的连接请求并建立连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
socket()函数返回的是服务器的套接字(以服务器为例),而accept()函数返回的套接字连接到调用 connect()的客户端,服务器通过该套接字与客户端进行数据交互
30.2.5 connect()函数
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
该函数用于客户端应用程序中,客户端调用 connect()函数将套接字 sockfd 与远程服务器进行连接
30.3 TCP Socket编程实例
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
/* socket
* bind
* listen
* accept
* send/recv
*/
#define SERVER_PORT 8888
#define BACKLOG 10
int main(int argc, char **argv)
{
int iSocketServer;
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
struct sockaddr_in tSocketClientAddr;
int iRet;
int iAddrLen;
int iRecvLen;
unsigned char ucRecvBuf[1000];
int iClientNum = -1;
signal(SIGCHLD,SIG_IGN);
iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == iSocketServer)
{
printf("socket error!\n");
return -1;
}
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
memset(tSocketServerAddr.sin_zero, 0, 8);
iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("bind error!\n");
return -1;
}
iRet = listen(iSocketServer, BACKLOG);
if (-1 == iRet)
{
printf("listen error!\n");
return -1;
}
while (1)
{
iAddrLen = sizeof(struct sockaddr);
iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (-1 != iSocketClient)
{
iClientNum++;
printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
if (!fork())
{
/* 子进程的源码 */
while (1)
{
/* 接收客户端发来的数据并显示出来 */
iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
if (iRecvLen <= 0)
{
close(iSocketClient);
return -1;
}
else
{
ucRecvBuf[iRecvLen] = '\0';
printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);
}
}
}
}
}
close(iSocketServer);
return 0;
}
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
/* socket
* connect
* send/recv
*/
#define SERVER_PORT 8888
int main(int argc, char **argv)
{
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
int iRet;
unsigned char ucSendBuf[1000];
int iSendLen;
if (argc != 2)
{
printf("Usage:\n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
iSocketClient = socket(AF_INET, SOCK_STREAM, 0);
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
{
printf("invalid server_ip\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);
iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("connect error!\n");
return -1;
}
while (1)
{
if (fgets(ucSendBuf, 999, stdin))
{
iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
if (iSendLen <= 0)
{
close(iSocketClient);
return -1;
}
}
}
return 0;
}
30.4 UDP Socket编程实例
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
/* socket
* bind
* sendto/recvfrom
*/
#define SERVER_PORT 8888
int main(int argc, char **argv)
{
int iSocketServer;
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
struct sockaddr_in tSocketClientAddr;
int iRet;
int iAddrLen;
int iRecvLen;
unsigned char ucRecvBuf[1000];
int iClientNum = -1;
//SOCK_DGRAM表示使用的是UDP协议
iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == iSocketServer)
{
printf("socket error!\n");
return -1;
}
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
memset(tSocketServerAddr.sin_zero, 0, 8);
iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("bind error!\n");
return -1;
}
while (1)
{
iAddrLen = sizeof(struct sockaddr);
iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (iRecvLen > 0)
{
ucRecvBuf[iRecvLen] = '\0';
printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
}
}
close(iSocketServer);
return 0;
}
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
/* socket
* connect
* send/recv
*/
#define SERVER_PORT 8888
int main(int argc, char **argv)
{
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
int iRet;
unsigned char ucSendBuf[1000];
int iSendLen;
int iAddrLen;
if (argc != 2)
{
printf("Usage:\n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
{
printf("invalid server_ip\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);
while (1)
{
if (fgets(ucSendBuf, 999, stdin))
{
iAddrLen = sizeof(struct sockaddr);
iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0,
(const struct sockaddr *)&tSocketServerAddr, iAddrLen);
#endif
if (iSendLen <= 0)
{
close(iSocketClient);
return -1;
}
}
}
return 0;
}
问题:试描述TCP建立和断开连接时的三次握手和四次挥手
建立连接:
A->B : SYN=1
B->A : SYN=1 + ACK=1
A->B : ACK=1
释放连接:
A->B : FIN=1
B->A : ACK
B->A : FIN=1
A->B : ACK
-
客户端先发送标志位SYN=1,seq=x请求与服务器建立连接2.
-
服务器收到客户端的TCP报文后,返回标志位SYN=1,ACK=1,seq=y,ack=x+1的报文应答客户端并同意建议连接
-
客户端收到服务器的TCP报文后,返回标志位ACK=1,seq=x+1,ack=y+1的报文表示接收到服务器的消息并建立连接
-
客户端向服务器发送标志位FIN=1,seq=x的报文请求断开连接2.
-
服务器收到后,返回标志位ACK=1,seq=y,ack=x+1的报文告诉客户端收到报文,并准备断开连接
-
服务器做好断开连接的准备后,给客户端发送标志位FIN=1,ACK=1,seq=u,ack=x+1的报文告诉客户端已做好准备断开连接
-
客户端收到报文后,返回标志位ACK=1,seq=x+1,ack=u+1的报文表示收到消息并断开连接
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)