TCP三次握手
回射客户/服务器
Socket函数
1.包含头文件<sys/socket.h>
2.功能:创建一个套接字用于通信
3.原型
int socket(int domain,int type,int protocol);
4.参数
domain:指定通信协议族
type:指定socket类型,流式套接字SOCK_STREAM(TCP),数据报套接字SOCK_DGRAM(UDP),原始套接字SOCK_RAM
protocol:协议类型
5.返回值:成功返回非负整数,它与文件描述符类似,我们把它称为套接字描述字,简称套接字。失败返回-1.
bind函数
1.包含头文件<sys/socket.h>
2.绑定一个本地地址到套接字
3.原型:
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
4.参数
sockfd:socket函数返回的套接字
addr:要绑定的地址
addrlen:地址长度
5.返回值:
成功返回0,失败返回-1
listen函数
1.包含头文件<sys/socket.h>
2.功能:将套接字用于监听进入的连接
3.原型:
int listen(int sockfd,int backlog);
4.参数
sockfd:socket函数返回的套接字
backlog:规定内核为此套接字排队的最大连接个数
5.返回值:
成功返回0,失败返回-1
一般来说,listen函数应该在调用socket函数和bind函数之后,调用函数accept之前。
对于给定的监听套接口,内核要维护两个队列:
1.已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程
2.已完成连接的队列
accept函数
1.包含头文件<sys/socket.h>
2.功能:从已完成连接队列返回第一个连接,如果已经完成连接队列为空,则阻塞。
3.原型 int accept(int socked,struct sockaddr *addr,socklen_t *addrlen);
4.参数
sockfd:服务器套接字
addr:将返回对等方的套接字地址
addrlen:返回对等方的套接字地址长度
5.返回值:成功非负整数,失败返回-1;
服务器端:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0); \ int main(void) { int listenfd; if((listenfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) { ERR_EXIT("socket"); } /*if(listenfd = socket(PF_INET,SOCK_STREAM,0)<0)*/ struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); //初始化 servaddr.sin_family = AF_INET; //地址族 servaddr.sin_port = htons(5188); //端口号 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /*seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/ /*iner_aton("127.0.0.1",&servaddr.sin_addr);*/ /*设置地址重复利用*/ int on = 1; if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) { ERR_EXIT("setsockopt"); } /*绑定*/ if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0 ) { ERR_EXIT("bind"); } /*绑定监听*/ if(listen(listenfd,SOMAXCONN) < 0) { ERR_EXIT("listen"); } struct sockaddr_in peeraddr; /*目标地址*/ socklen_t peerlen = sizeof(peeraddr); int conn; /*已连接套接字*/ /*等待连接*/ if( (conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0 ) { ERR_EXIT("accept"); } else { printf("ip = %s,port = %d\n",inet_ntoa(peeraddr.sin_addr),peeraddr.sin_port); char recvbuf[1024]; while(1) { memset(recvbuf,0,sizeof(recvbuf)); int ret = read(conn,recvbuf,sizeof(recvbuf)); fputs(recvbuf,stdout); write(conn,recvbuf,ret); } } close(conn); close(listenfd); return 0; }
客户端:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0); \ int main(void) { int sock; char sendbuf[1024] = {0}; char recvbuf[1024] = {0}; if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) { ERR_EXIT("socket"); } /*if(listenfd = socket(PF_INET,SOCK_STREAM,0)<0)*/ struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); //初始化 servaddr.sin_family = AF_INET; //地址族 servaddr.sin_port = htons(5188); //端口号 /*servaddr.sin_addr.s_addr = htonl(INADDR_ANY);*/ servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); /*iner_aton("127.0.0.1",&servaddr.sin_addr);*/ if( connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0) { ERR_EXIT("connect"); } else { printf("ip = %s,port = %d\n",inet_ntoa(servaddr.sin_addr),servaddr.sin_port); while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL) { write(sock,sendbuf,strlen(sendbuf)); read(sock,recvbuf,sizeof(recvbuf)); fputs(recvbuf,stdout); memset(sendbuf,0,sizeof(sendbuf)); memset(recvbuf,0,sizeof(recvbuf)); } } close(sock); return 0; }
测试效果: