TCP、UDP网络编程
-
基本概念
- TCP
- 可靠、有重传机制、速度慢、有链接
- UDP
- 不可靠、速度快、无链接
- TCP
-
通信三要素
源、目的、长度
客户端主动地发起请求、服务器被动地响应请求
-
TCP建立传输
-
服务器端
- 创建一个套接字
#include <sys/socket.h> int socket(int domain, int type, int protocol); /* domain:AF_INET、AF_INET6、AF_UNIX type:SOCK_STREAM、SOCK_DGRAM protocol: 0 返回值: 成功: 新套接字所对应文件描述符 失败: -1 errno */
- 绑定地址结构
#include <arpa/inet.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); /* sockfd: socket 函数返回值 struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(8888); addr.sin_addr.s_addr = htonl(INADDR_ANY); addr: 传入参数(struct sockaddr *)&addr addrlen: sizeof(addr) 地址结构的大小。 返回值: 成功:0 失败:-1 errno */
- 设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量)
int listen(int sockfd, int backlog); /* sockfd: socket 函数返回值 backlog:上限数值。最大值 128. 返回值: 成功:0 失败:-1 errno */
- 阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的socket文件描述符。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); /* sockfd: 客户端socket 函数返回值 addr:传出参数。成功与服务器建立连接的那个客户端的地址结构(IP+port) socklen_t clit_addr_len = sizeof(addr); addrlen:传入传出。 &clit_addr_len 入:addr的大小。 出:客户端addr实际大小。 返回值: 成功:能与客户端进行数据通信的 socket 对应的文件描述。 失败: -1 , errno */
- 接收数据
#include <sys/types.h> #include <sys/socket.h> ssize_t recv(int sockfd, void *buf, size_t len, int flags); /* sockfd: 服务器端socket 函数返回值 buf:接收数据buffer len:要接受数据的大小,buffer-1 flags:0 返回值: 成功:返回接收到的字节数 失败: -1 , errno */
代码示例
#include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> #include <netinet/in.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <signal.h> #define SERVER_PORT 8888 #define BACKLOG 10 /* * Socket * bind * listen * accept * send/receive */ int main(int argc, char **argv) { int iSocketServer; int iSocketClient; int iRet; int iRecvLen; struct sockaddr_in tSocketServerAddr; struct sockaddr_in tSocketClientAddr; 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 = htonl(INADDR_ANY); memset(tSocketServerAddr.sin_zero, 0, 8); iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(tSocketServerAddr)); if (iRet == -1) { printf("bind error\n"); return -1; } iRet = listen(iSocketServer, BACKLOG); if (iRet == -1) { printf("listen error\n"); return -1; } while(1) { socklen_t 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 message from client %d: %s", iClientNum, ucRecvBuf); } } } } } close(iSocketServer); return 0; }
-
客户端
-
创建socket
-
与服务器建立连接
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); /* sockfd: socket 函数返回值 struct sockaddr_in srv_addr; // 服务器地址结构 srv_addr.sin_family = AF_INET; srv_addr.sin_port = 9527 跟服务器bind时设定的 port 完全一致。 inet_pton(AF_INET, "服务器的IP地址",&srv_adrr.sin_addr.s_addr); addr:传入参数。服务器的地址结构 addrlen:服务器的地址结构的大小 返回值: 成功:0 失败:-1 errno */
- 发送数据
#include <sys/types.h> #include <sys/socket.h> ssize_t send(int sockfd, const void *buf, size_t len, int flags); /* sockfd:客户端socket 函数返回值 buf:发送数据的buffer len:实际发送的字节数strlen(buf) flags:0 */
代码示例
#include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> #include <netinet/in.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #define SERVER_PORT 8888 /* *socket *connect *send */ int main(int argc, char **argv) { int iSocketClient; int iRet; int iSendLen; struct sockaddr_in tSocketServerAddr; unsigned char ucSendBuf[1000]; 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\n"); return -1; } tSocketServerAddr.sin_family = AF_INET; tSocketServerAddr.sin_port = htons(SERVER_PORT); //host to net short //tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); if(0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)) { printf("invalid server_ip\n"); return -1; } iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); if (-1 == iSocketClient) { 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; }
-
-
-
UDP建立传输
-
服务器端
-
创建socket
-
绑定地址结构
-
recvfrom
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); /* sockfd: 服务端socket 函数返回值 buf:接收数据buffer len:要接受数据的大小,buffer-1 flags:0 src_addr:客户端的地址结构 addrlen:地址结构大小 返回值: 成功:返回接收到的字节数 失败: -1 , errno */
代码示例
#include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> #include <netinet/in.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #define SERVER_PORT 8888 #define BACKLOG 10 /* * Socket * bind * sendto/recvfrom */ int main(int argc, char **argv) { int iSocketServer; int iSocketClient; int iRet; int iRecvLen; int iAddrLen; struct sockaddr_in tSocketServerAddr; struct sockaddr_in tSocketClientAddr; unsigned char ucRecvBuf[1000]; int iClientNum = -1; 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 = htonl(INADDR_ANY); memset(tSocketServerAddr.sin_zero, 0, 8); iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(tSocketServerAddr)); if (iRet == -1) { 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 message from %s : %s", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf); } } close(iSocketServer); return 0; }
-
-
客户端
-
创建socket
-
sendto
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); /* sockfd:客户端socket 函数返回值 buf:发送数据的buffer len:实际发送的字节数strlen(buf) flags:0 dest_addr:送达的服务器端地址结构 addrlen:地址结构大小 */
代码示例
#include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> #include <netinet/in.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #define SERVER_PORT 8888 /* *socket *sendto */ int main(int argc, char **argv) { int iSocketClient; int iRet; int iSendLen; int iAddrLen; struct sockaddr_in tSocketServerAddr; unsigned char ucSendBuf[1000]; 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\n"); return -1; } tSocketServerAddr.sin_family = AF_INET; tSocketServerAddr.sin_port = htons(SERVER_PORT); //host to net short //tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); if(0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)) { printf("invalid server_ip\n"); return -1; } while (1) { if(fgets(ucSendBuf, 999, stdin)) { iAddrLen = sizeof(struct sockaddr); iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0, (const struct sockaddr*)&tSocketServerAddr, iAddrLen); if (iSendLen <= 0) { close(iSocketClient); return -1; } } } return 0; }
-
-