网络通信
网络通信概述
IP和端口
数据传输三要素:源、目的、长度 (网络传输中使用“IP和端口”表示源或目的)
网络传输两个对象(server、client)
两种传输方式:TCP/UDP
TCP和UDP原理上的区别
TCP/UDP网络通信交互图(1为tcp,2为udp)
网络编程主要函数
socket函数
int socket(int domain, int type, int protocol);
bind函数
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
listen函数
int listen(int sockfd, int backlog);
accept函数
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
connect函数
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
send函数
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
recv函数
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
recvfrom函数
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
sendto函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
TCP编程
server
#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 // listen函数中最大同时监听连接数
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); // 忽略子进程退出信号,避免僵尸进程
// 1.创建套接字 远程通信,TCP协议,0默认
// 执行成功返回文件描述符,失败返回-1
iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == iSocketServer)
{
printf("socket error!\n");
return -1;
}
tSocketServerAddr.sin_family = AF_INET; // 网络通信
// htons:主机字节序转网络字节序
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; // 表示可以和任何主机通信
memset(tSocketServerAddr.sin_zero, 0, 8); // 填充0
// 2.绑定本地地址和端口
iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("bind error!\n");
return -1;
}
// 3.监听 10个连接
iRet = listen(iSocketServer, BACKLOG);
if (-1 == iRet)
{
printf("listen error!\n");
return -1;
}
while (1)
{
iAddrLen = sizeof(struct sockaddr);
/* 调用accept函数来等待客户端来连接,客户连接成功返回一个值,连接失败返回-1; */
iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (-1 != iSocketClient)
{
iClientNum++;
/* 支持多个客户端连接,每有一个就调用fork(),并创建一个子进程 */
// inet_ntoa:将网络字节序IP地址转换为点分十进制IP地址
printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
if (!fork()) /* 执行到fork()后马上复制一个代码完全一样的子进程*/
{
/* 父进程走fork()=0;子进程走fork()!=0; */
// fork函数:创建一个子进程,父进程返回子进程ID,子进程返回0 子进程的PID=父进程PID+1
/*子进程的源码*/
while (1)
{
/* 接受客户端发来的数据并显示出来 */
iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
if (iRecvLen <= 0)
{
close(iSocketClient); /* 一直接受客户端传来的消息 */ // 关闭客户端套接字
return -1;
}
else
{
ucRecvBuf[iRecvLen] = '\0'; /* 接受到的数据以'\0'结尾 */
printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);
}
}
}
}
}
close(iSocketServer); // 关闭服务器套接字
return 0;
}
client
#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;
}
// 1.创建套接字
iSocketClient = socket(AF_INET, SOCK_STREAM, 0); // 远程通信,TCP协议,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);
// 2.发送连接请求连接服务器
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))
{
// 3.发送数据
iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
if (iSendLen <= 0)
{
// 4.关闭套接字
close(iSocketClient);
return -1;
}
}
}
return 0;
}
执行过程:在linux下先编译两个程序,然后执行server再打开新终端执行client,执行需要输入ip地址,此时在客户端发送字符串,服务器端可以接收到字符串
UDP编程
server
#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;
// 1.创建socket套接字
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);
// 2.绑定本地ip地址和端口号
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);
// 3.接收数据 recvfrom常用于无连接的udp通信
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);
}
}
// 4.关闭socket套接字
close(iSocketServer);
return 0;
}
client
#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;
}
// 1.创建socket套接字
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);
// 2.连接服务器
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))
{
// 3.发送数据
iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
if (iSendLen <= 0)
{
// 4.关闭套接字
close(iSocketClient);
return -1;
}
}
}
return 0;
}
总结:TCP和UPD编程的区别
TCP | UDP | |
---|---|---|
client | socket->connect->send/recv | socket->connect->send/recv(可以直接使用sendto,去掉connect) |
server | socket->bind->listen->accept->send/recv | socket->bind->sendto/recvfrom |