Linux下TCP/socket编程
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文!
本博客全网唯一合法URL:http://www.cnblogs.com/acm-icpcer/p/9073801.html
(本篇博客参考了:https://www.cnblogs.com/xiaojiang1025/archive/2016/10/11/5950458.html,源码为我自己所写)
基本模型:
核心代码:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> //服务器: socket() //创建socket struct sockaddr_in //准备通信地址 bind() //绑定socket和addr listen() //创建listening socket accept() //创建connect socket send()/recv() //进行通信 close() //关闭socket //客户端: socket() //创建socket 准备通信地址:服务器的地址 connect() //链接socket和通信地址 send()/recv() //进行通信 close() //关闭socket
关键函数解释:
bind()
//把通信地址和socket文件描述符绑定,用在服务器端,成功返回0,失败返回-1设errno
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd: socket文件的fd(returned by socket())
addr: 需要强制类型转换成socketaddr_un或soketaddr_in, 参见上
addrlen: 通信地址的大小, 使用sizeof();
listen()
//创建侦听socket,把sockfd标记的socket标记为被动socket,被动socket表示这个socket只能用来接收即将到来的连接请求,不再用于读写操作和通信,接收连接请求的是accept()
//成功返回0,失败返回-1设errno
int listen(int sockfd, int backlog);
backlog:排队等待“被响应”连接请求队列的最大长度 eg: 接待室的最大长度
accept()
//创建连接socket,返回连接socket的文件描述符,成功返回文件描述符,失败返回-1设errno
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
addr : 结构体指针, 用于带出客户端的通信地址
addlen : 结构体指针, 用于带出通信地址的大小
ATTENTION: listen()把socket()创建的sockfd变为listening socket, 负责侦听哪个client连接上了(即不但要知道连上没, 还要知道谁连上了, 这个SOCK_STREAM的socket有这个能力), accept()提取排队中的最上面的一个client, 给它一个conneted socket, 这样这个client就可以和server沟通了, 就是说这里有两个socket, 一个负责侦听一个负责通信
send()
//向指定的socket发送指定的数据,成功返回实际发送数据的大小,失败返回-1设errno
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
sockfd: 用于通信的socket描述符(returned by accept())
buf : 被发送数据的缓冲区首地址
len : 被发送数据的大小
flags: 发送的标志, 如果给0等同于write()
recv()
//从指定的socket接收数据,成功返回接收的数据的大小,失败返回-1设errno
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
sockfd: 用于通信的socket描述符(returned by accept())
buf: 接收数据的缓冲区首地址
len: 接收数据的大小
flags: 发送的标志, 如果给0等同于read()
connect()
//初始化一个socket的连接,用在客户端,成功返回0,失败返回-1设errno
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd: socket文件的fd(returned by socket())
addr: 需要强制类型转换成socketaddr_un或soketaddr_in, 参见上
addrlen: 通信地址的大小, 使用sizeof();
源代码:
1、client端:
/* ./server (local ip) 7575 自己ip 端口 */ #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <resolv.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #define MAXBUF 1024 int main(int argc, char **argv) { int sockfd, len; struct sockaddr_in dest; char buffer[MAXBUF + 1]; if (argc != 3) { printf(" error format,it must be:\n\t\t%s IP port\n",argv[0]); exit(EXIT_FAILURE); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Socket"); exit(errno); } printf("socket created\n"); bzero(&dest, sizeof(dest)); dest.sin_family = AF_INET; dest.sin_port = htons(atoi(argv[2])); if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) { perror(argv[1]); exit(errno); } if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest))==-1) { perror("Connect "); exit(errno); } printf("server connected\n"); while (1) { bzero(buffer, MAXBUF + 1); len = recv(sockfd, buffer, MAXBUF, 0); if (len > 0) printf("recv successful:'%s',%d byte recv\n",buffer, len); else { if (len < 0) printf("send failure,errno code is %d,err message is '%s'\n",errno, strerror(errno)); else printf("the other one close ,quit\n"); break; } bzero(buffer, MAXBUF + 1); printf("pls send message to send:"); fgets(buffer, MAXBUF, stdin); if (!strncasecmp(buffer, "quit", 4)) { printf(" i will quit!\n"); break; } len = send(sockfd, buffer, strlen(buffer) - 1, 0); if (len < 0) { printf("message '%s' send failure,errno code is %d,errno message is '%s'\n",buffer, errno, strerror(errno)); break; } else printf("message:%s\tsend successful,%dbyte send!\n",buffer, len); } close(sockfd); return 0; }
2、server端:
/* ./server (local ip) 7575 5 自己ip 端口 等待队列大小 ifconfig -a */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/wait.h> #include <unistd.h> #include <arpa/inet.h> #define MAXBUF 1024 int main(int argc, char *argv[]) { int pid; int sockfd, new_fd; socklen_t len; struct sockaddr_in my_addr, their_addr; unsigned int myport, lisnum; char buf[MAXBUF + 1]; if (argv[2]) myport = atoi(argv[2]); else myport = 7575; if (argv[3]) lisnum = atoi(argv[3]); else lisnum = 5; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(EXIT_FAILURE); } bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(myport); if (argv[1]) my_addr.sin_addr.s_addr = inet_addr(argv[1]); else my_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))== -1) { perror("bind"); exit(EXIT_FAILURE); } if (listen(sockfd,lisnum ) == -1) { perror("listen"); exit(EXIT_FAILURE); } printf("wait for connect\n"); len = sizeof(struct sockaddr); if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1) { perror("accept"); exit(EXIT_FAILURE); } else printf("server: got connection from %s, port %d, socket %d\n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd); while (1) { printf("newfd=%d\n",new_fd); bzero(buf, MAXBUF + 1); printf("input the message to send:"); fgets(buf, MAXBUF, stdin); if (!strncasecmp(buf, "quit", 4)) { printf("i will close the connect!\n"); break; } len = send(new_fd, buf, strlen(buf) - 1, 0); if (len > 0) printf("message:%s\t send sucessful,send %dbyte!\n",buf, len); else { printf("message'%s' send failure!errno code is %d,errno message is '%s'\n",buf, errno, strerror(errno)); break; } bzero(buf, MAXBUF + 1); len = recv(new_fd, buf, MAXBUF, 0); if (len > 0) printf("message recv successful :'%s',%dByte recv\n",buf, len); else { if (len < 0) printf("recv failure!errno code is %d,errno message is '%s'\n",errno, strerror(errno)); else printf("the other one close quit\n"); break; } } close(new_fd); close(sockfd); return 0; }
运行示例:
PS(被蔡总玩坏了的tcp,23333):
tz@COI HZAU
2018/5/22