目录
- 1、网络编程概念
- 2、网络编程的API
- 2.1 网络通信交互示意图
- 2.2 主要API
- 3、编程测试
- 3.1 TCP 测试
- 3.1.1 server 程序
- 3.1.2 Client 程序
- 3.1.3 测试结果
- 3.2 UDP 测试
- 3.2.1 udp server
- 3.2.2 udp client
- 3.2.3 测试结果
1、网络编程概念
1.数据传输三要素:源、目的、长度。在网络传输中需要使用 IP+端口来表示源和目的。
2.网络传输中的两个对象:server 和 client
- server:被动响应请求
- client:主动发起请求
3.两种传输方式:TCP/UDP
- TCP: 可靠传输
- UDP:不可靠传输 (传输视频),无连接。
2、网络编程的API
2.1 网络通信交互示意图
1.TCP
2.UDP
2.2 主要API
1.创建1个套接字
int socket(int domain, int type, int protocol);
- domain:网络程序所在的主机采用的通信协议族。AF_INET
- type: 网络程序所采用的通信协议.SOCK_STREAM, TCP协议;SOCK_DGRAM,UDP协议。
- protocol:由于指定了type,此值设置为0
- 返回值: 成功,返回文件描述符;失败,返回-1.2.将本地的地址和端口同socket绑定
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
- sockfd:要绑定的套接字描述符
- addr:sockaddr 结构体指针,由于系统兼容性一般使用struct sockaddr_in来代替- struct sockaddr_in{unsigned short sin_family; unsigned short sin_port;struct in_addr sin_addr;unsigned char sin_zero[8];}sin_family: AF_INETsin_port: 要监听的端口号sin_addr: INADDR_ANY,表示可以和任何的主机通信
- addrlen:sockaddr结构的长度
- 返回值:成功返回0;失败返回-13.启动监测数据
int listen(int sockfd,int backlog);
- sockfd:bind后的文件描述符;
- backlog:请求排队的最大长度。多个client连接时,可以接受的排队数量。
- 返回值:成功返回0;失败返回-14.接受一个连接
int accept(int sockfd, struct sockaddr *addr,int *addrlen);
- sockfd:listen后的文件描述符;
- addr、addrlen:给client程序填写的,server端只要传递指针即可。5. client向server发起一个连接
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
- sockfd:socket函数返回的文件描述符;
- addr:server端的地址和端口信息
- addrlen:sockaddr 的长度
- 返回值:成功返回0;失败返回-16. client/server 发送数据函数
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
- sockfd:套接字描述符
- buf:要发送数据缓冲区
- len:实际要发送的数据的字节数
- flags:一般设置为0
- 返回值:成功返回实际发送数据的字节数; 失败返回-17.client/server 接收数据函数
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
- sockfd:套接字描述符
- buf:用于存放接收数据的缓冲区
- len:buf长度
- flags:一般设置为0
- 返回值:成功返回实际接收数据的字节数; 失败返回-18.udp 接收函数
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
- sockfd:套接字描述符
- buf:用于存放接收数据的缓冲区
- len:buf长度
- flags:一般设置为0
- src_addr:源地址结构体
- addrlen:源地址结构体长度指针
- 返回值:成功返回实际接收数据的字节数; 失败返回-19.udp 发送函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
- sockfd:套接字描述符
- buf:用于存放接收数据的缓冲区
- len:buf长度
- flags:一般设置为0
- src_addr:源地址结构体
- addrlen:源地址结构体长度
- 返回值:成功返回实际发送数据的字节数; 失败返回-1
3、编程测试
3.1 TCP 测试
3.1.1 server 程序
server 程序有1个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 <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>#define SERVER_PORT 1234
#define BACKLOG 10/* socket* bind* listen* accept* send/recv*/
int main( int argc, char **argv)
{int iSocketServer;int iSocketClient;int iRet;struct sockaddr_in tSocketServerAddr;struct sockaddr_in tSocketClientAddr;int iAddrLen;int iClientNum = -1;int iRecvLen;unsigned char RecvBuf[512];signal(SIGCHLD, SIG_IGN); // 处理client关闭后server僵尸进程iSocketServer = socket(AF_INET, SOCK_STREAM, 0);if(-1 == iSocketServer){printf("socket error!\r\n");return -1;}tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_port = htons(SERVER_PORT);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!\r\n");return -1;}iRet = listen(iSocketServer, BACKLOG);if(-1 == iRet){printf("listen error!\r\n");return -1;}while(1){iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);if(-1 != iSocketClient){iClientNum++;printf("Get connect from %d:%s\r\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr)); // inet_ntoa缃戠粶鍦板潃杞崲鎴愬瓧绗︿覆if(!fork()){// 瀛愯繘绋嬩唬鐮?while(1){// 鎺ユ敹瀹㈡埛绔暟鎹苟鏄剧ずiRecvLen = recv(iSocketClient, RecvBuf, 511, 0);if(iRecvLen <= 0){printf("Recv error\n");close(iSocketClient);return -1;}else{RecvBuf[iRecvLen] = '\0';printf("Get Msg from client %d: %s\r\n", iClientNum, RecvBuf);}}}}}close(iSocketServer);return 0;
}
3.1.2 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 <sys/types.h>
#include <unistd.h>
#include <stdio.h>#define SERVER_PORT 1234/* socket* connect * send/recv*/
int main( int argc, char **argv)
{int iSocketClient;int iRet;struct sockaddr_in tSocketServerAddr; unsigned char SendBuf[512];int iSendLen;if(argc != 2){printf("Usage:\n");printf("%s <server_ip>:\n",argv[0]);return -1;}iSocketClient = socket(AF_INET, SOCK_STREAM, 0);if(-1 == iSocketClient){printf("socket error!\r\n");return -1;}tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_port = htons(SERVER_PORT);if(0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)){printf("invailed server ip!\r\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!\r\n");return -1;}while(1){if(fgets(SendBuf, 511, stdin)){iSendLen = send(iSocketClient, SendBuf, strlen(SendBuf), 0);if(iSendLen <= 0){printf("Recv error\n");close(iSocketClient);return -1;}}}
}
3.1.3 测试结果
1.client 1 连接server 发送数据
2.Client2 连接server发送数据
3.server 接收数据
4.当关闭一个Client后,server没有僵尸进程
3.2 UDP 测试
3.2.1 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 <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>#define SERVER_PORT 1234
#define BACKLOG 10/* socket* bind* sendto /recvfrom*/
int main( int argc, char **argv)
{int iSocketServer;int iSocketClient;int iRet;struct sockaddr_in tSocketServerAddr;struct sockaddr_in tSocketClientAddr;int iAddrLen;int iRecvLen;unsigned char RecvBuf[512];signal(SIGCHLD, SIG_IGN); iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);if(-1 == iSocketServer){printf("socket error!\r\n");return -1;}tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_port = htons(SERVER_PORT);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!\r\n");return -1;}while(1){iAddrLen = sizeof(struct sockaddr);iRecvLen = recvfrom(iSocketServer, RecvBuf, 511, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);if(iRecvLen > 0){RecvBuf[iRecvLen] = '\0';printf("Get Msg from client %s: %s\r\n", inet_ntoa(tSocketClientAddr.sin_addr), RecvBuf);}}close(iSocketServer);return 0;
}
3.2.2 udp 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 <sys/types.h>
#include <unistd.h>
#include <stdio.h>#define SERVER_PORT 1234/* socket* sendto/recvfrom**/
int main( int argc, char **argv)
{int iSocketClient;int iRet;struct sockaddr_in tSocketServerAddr; unsigned char SendBuf[512];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);if(-1 == iSocketClient){printf("socket error!\r\n");return -1;}tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_port = htons(SERVER_PORT);if(0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)){printf("invailed server ip!\r\n");return -1;}memset(tSocketServerAddr.sin_zero, 0, 8);while(1){if(fgets(SendBuf, 511, stdin)){iAddrLen = sizeof(struct sockaddr);iSendLen = sendto(iSocketClient, SendBuf, strlen(SendBuf), 0,(const struct sockaddr *)&tSocketServerAddr, iAddrLen);if(iSendLen <= 0){printf("Recv error\n");close(iSocketClient);return -1;}}}
}
3.2.3 测试结果
1.udp client 1 发送数据
2.udp client2 发送数据
3.udp server 接收数据
To Be Continue …