Welcome 微信登录

首页 / 操作系统 / Linux / Linux socket tcp/ip编程

模型

服务器:
  1. 创建socket: socket()
  2. 准备通信地址: struct sockaddr_in
  3. 绑定socket和addr: bind()
  4. 创建listening socket:listen()
  5. 创建connect socket: accept()
  6. 进行通信: send()/recv()
  7. 关闭socket: close()
客户端:
  1. 创建socket:socket()
  2. 准备通信地址:服务器的地址
  3. 链接socket和通信地址:connect()
  4. 进行通信:send()/recv()
  5. 关闭socket:close()

头文件

#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>

listen()

//创建侦听socket,把sockfd标记的socket标记为被动socket,被动socket表示这个socket只能用来接收即将到来的连接请求,不再用于读写操作和通信,接收连接请求的是accept()//成功返回0,失败返回-1设errnoint listen(int sockfd, int backlog);backlog:排队等待“被响应”连接请求队列的最大长度 eg: 接待室的最大长度

accept()

//创建连接socket,返回连接socket的文件描述符,成功返回文件描述符,失败返回-1设errnoint 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设errnossize_t send(int sockfd, const void *buf, size_t len, int flags);sockfd: 用于通信的socket描述符(returned by accept())
buf : 被发送数据的缓冲区首地址
len : 被发送数据的大小
flags: 发送的标志, 默认给0

recv()

//从指定的socket接收数据,成功返回接收的数据的大小,失败返回-1设errnossize_t recv(int sockfd, void *buf, size_t len, int flags);sockfd: 用于通信的socket描述符(returned by accept())
buf: 接收数据的缓冲区首地址
len: 接收数据的大小
flags: 发送的标志, 默认给0

例子

// tcp/ip server七步走#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>int main(){_//1.创建socketsocket()int sockfd=socket(AF_INET,SOCK_STREAM,0);if(-1==sockfd)perror("socket"),exit(-1);printf("creat socket success ");//2.准备通信地址(服务器地址),使用结构体类型struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(8888);addr.sin_addr.s_addr=inet_addr("176.43.11.211");//client也用这个server的地址//3.绑定socket和通信地址,使用bind()int res=bind(sockfd, (struct sockaddr*)&addr,sizeof(addr)); //client用connectif(-1==res)perror("bind"),exit(-1);printf("bind success ");//4.生成侦听socket: listening socketlisten()//client可没有这一步res=listen(sockfd,100);if(-1==res)perror("listen"),exit(-1);printf("listen success ");//5.响应客户端连接请求并生成connected socket accept() //client当然没有这一步struct sockaddr_in recv_addr;socklen_t len=sizeof(recv_addr);int CnnSockfd=accept(sockfd,(struct sockaddr*)&recv_addr,&len);if(-1==fd)perror("accept"),exit(-1);char* ip=inet_ntoa(recv_addr.sin_addr); //存储client的ipprintf("client$%s connect success ",ip);//6.进行通信 send()/recv()char buf[100]={0};res=recv(CnnSockfd,buf,sizeof(buf),0);//client是send()if(-1==res)perror("recv"),exit(-1);printf("client %s sent data:%s, size is:%d ",ip,buf,res);res=send(CnnSockfd,"I received",12,0);//client是recv()if(-1==res)perror("send"),exit(-1);printf("send data success, size is:%d ",res);//7.关闭listening socket和connect socket close() //client只关闭sockfd就行, 因为就这一个fdres=close(CnnSockfd);if(-1==res)perror("close"),exit(-1);res=close(sockfd);if(-1==res)perror("close"),exit(-1);printf("close success ");return 0;}//创建server, 用多进程同时响应多个client的请求, 当client发来 “bye”的时候断开连接, 按下Ctrl+C关闭服务器#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>//省略了几个头文件int sockfd; //全局变量void fa(int signo){printf("closing server... ");sleep(3);int res=close(sockfd);if(-1==res)perror("close"),exit(-1);printf("server closed ");exit(0);}int main(){… //同上一个程序//set SIGINTprintf("Press ctrl+c to close server ");if(SIG_ERR==signal(SIGINT,fa))//整个程序,包括第一个while(1)是通过信号处理终止的perror("signal"),exit(-1); while(1){ //只要有client接入就创建新进程与之通信struct sockaddr_in recv_addr;socklen_t len=sizeof(recv_addr);int CnnSockfd=accept(sockfd,(struct sockaddr*)&recv_addr,&len); //如果侦听队列里面有client就accept(), 否则就在这阻塞着,不继续执行,除非遇到Ctrl+C终止整个进程if(-1==CnnSockfd)perror("accept"),exit(-1);char *ip=inet_ntoa(recv_addr.sin_addr);printf("client:%s linked ",ip);pid_t pid=fork();if(-1==pid)perror("fork()"),exit(-1);if(0==pid){if(SIG_ERR==signal(SIGINT,SIG_DFL))perror("signal"),exit(-1);res=close(sockfd);//每个child处理一个client,所以已经不需要listening socket了,可以把它关了if(-1==res)perror("close"),exit(-1);while(1){ //只要client发数据就处理,除非遇到 “bye”char buf[100]={0};res=recv(CnnSockfd,buf,sizeof(buf),0);if(-1==res)perror("recv"),exit(-1);printf("client%s,data sent:%s ",ip,buf);if(!strcmp(buf,"bye")){ //遇到“bye”就不再待命,break掉准备断开连接printf("client%s has been unlinked ",ip);break;}res=send(CnnSockfd,"I received!",12,0);if(-1==res)perror("send"),exit(-1);}res=close(CnnSockfd); //断开连接即close(相应的connected socket)if(-1== res)perror("close"),exit(-1);exit(0);//断开了连接了,就可以exit子进程了}res=close(CnnSockfd); //if(-1==res)perror("close"),exit(-1);}return 0;}本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-10/135944.htm