tcp通信
TCP通信,理解都在注释里,看着敲敲。
TCP的三次握手可以看http://www.cnblogs.com/leezhxing/p/4524176.html可以看出listen()函数阶段完成的三次握手,accept()时三次握手已经完成。
关于listen函数的backlog参数可以看:http://blog.chinaunix.net/uid-24782829-id-3456109.html
tcp_client.c
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> /* struct hostent 需要 */ #define PORT 4321 /* server端口 */ #define MAXSIZE 100 int main(int argc, char *argv[]) { int sockfd; //socket文件描述符 int num; //用于存储接收和发送的字节数 char buf[MAXSIZE]; //用于recv的接收字符数组 struct hostent *he; //通过域名获取IP struct sockaddr_in server; //存储server的socket信息 /* 例如: ./tcp_client.out 127.0.0.1 */ if (argc != 2) { printf("Usage: %s <IP Address>\n",argv[0]); exit(1); } if((he=gethostbyname(argv[1]))==NULL) { printf("gethostbyname() error\n"); exit(1); } //建立socket if((sockfd=socket(AF_INET,SOCK_STREAM, 0))==-1) { printf("socket() error\n"); exit(1); } //server端的socket信息 bzero(&server,sizeof(server)); //先清空server server.sin_family = AF_INET; server.sin_port = htons(PORT); //转为网络字节序 server.sin_addr = *((struct in_addr *)he->h_addr); //看udp的client的解释 if(connect(sockfd, (struct sockaddr *)&server, sizeof(server))==-1) { printf("connect() error\n"); exit(1); } char str[] = "hello\n"; //send成功返回发送的字节数,失败返回-1 if((num=send(sockfd,str,sizeof(str),0))==-1){ printf("send() error\n"); exit(1); } //recv成功返回接收的字节数,失败返回-1 if((num=recv(sockfd,buf,MAXSIZE,0))==-1) { printf("recv() error\n"); exit(1); } buf[num-1]='\0'; printf("server message: %s\n",buf); close(sockfd); return 0; }
tcp_server.c
#include <sys/time.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 4321 //占用端口 #define BACKLOG 1 //定义侦听队列长度 #define MAXSIZE 1024 int main(int argc, char *argv[]) { char buf[MAXSIZE]; //recv()接收用字符数组 int listenfd, connectfd; struct sockaddr_in server; struct sockaddr_in client; socklen_t addrlen; //存储struct sockaddr_in的长度 //建立TCP SOCKET if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { /* handle exception */ perror("socket() error. Failed to initiate a socket"); exit(1); } //填充socket信息 bzero(&server, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = htonl(INADDR_ANY); //接收任意连接 //bind if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1) { /* handle exception */ perror("Bind() error."); exit(1); } //listen if(listen(listenfd, BACKLOG) == -1) { perror("listen() error. \n"); exit(1); } addrlen = sizeof(client); //等同于sizeof(struct sockaddr_in) while(1){ /* * accept函数返回一个新的sockfd,之后的操作都会在这个fd上进行 * 系统会把远端端的socket信息都存储在client上 * addrlen是地址 */ if((connectfd=accept(listenfd,(struct sockaddr *)&client, &addrlen))==-1) { perror("accept() error. \n"); exit(1); } struct timeval tv; gettimeofday(&tv, NULL); //获取微妙级时间,具体看手册 printf("client's ip %s, port %d at time %ld.%ld\n",inet_ntoa(client.sin_addr),htons(client.sin_port), tv.tv_sec,tv.tv_usec); int iret=-1; //初始化接收字节的长度 while(1) { iret = recv(connectfd, buf, MAXSIZE, 0); if(iret>0){ printf("%s\n", buf); }else{ close(connectfd); break; } //发送接收到的信息给client send(connectfd, buf, iret, 0); } } close(listenfd); return 0; }