分析一个socket通信: server/client
分析一个socket通信: server/client1
server
1. 创建一个server_socket文件,并绑定端口,然后监听端口 (socket, bind, listen)
2. 查询该端口是否有客户端的连接:
while(1)
{
查询这个端口是否有来自client的消息;(accept)// accept: input is server_socket_fd ; ret value is client_socket_fd
如果有,返回client_socket_fd, 并把消息读出来 (rcv from client_socket_fd); 当然这个时候server也可以send to client_socket.
}
client
1. 创建一个client_socket文件,绑定端口和server ip,然后通过这个socket去和server的socket连接起来 (socket, connect);
2. 连接成功后,client往client_socket写东西(send to client_socket_fd). 当然这个时候client也可以rcv from client_socket.
client_socket文件的作用是client和server之间的一个通信管道。
debug代码:
//client: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #define N 128 typedef struct sockaddr SA; extern void show_time(void); int main(int argc, char *argv[]) { int sockfd, fd, nbyte; char command[32]; struct sockaddr_in server_addr; if (argc < 3) { printf("Usage : %s <server_ip> : <port>\n", argv[0]); exit(-1); } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = PF_INET; server_addr.sin_port = htons(atoi(argv[2])); server_addr.sin_addr.s_addr = inet_addr(argv[1]); while ( 1 ) { printf("<client> "); fgets(command, 32, stdin); command[strlen(command)-1] = '\0'; // overwrite the '\n' if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { printf("fail to get\n"); return; } printf("socket\n");show_time(); if (connect(sockfd, (SA *)&server_addr, sizeof(server_addr)) < 0) { printf("fail to connect server\n"); return; } printf("send\n");show_time(); send(sockfd, command, strlen(command)+1, 0); printf("send over\n");show_time(); close(sockfd); } return 0; } //break client.c:41
//server: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <dirent.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #define N 128 typedef struct sockaddr SA; extern void show_time(void); int main(int argc, char *argv[]) { int listenfd, connfd; char buf[N]; struct sockaddr_in server_addr; // XXX:step 1 int socket(int domain, int type, int protocol); if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "fail to socket : %s\n", strerror(errno)); exit(-1); } #ifdef _DEBUG_ printf("socket is %d\n", listenfd); #endif // XXX:step 2 int bind(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen); memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = PF_INET; server_addr.sin_port = htons(8888); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listenfd, (SA *)&server_addr, sizeof(server_addr)) < 0) { perror("fail to bind"); exit(-1); } listen(listenfd, 5); static int counter = 0; while ( 1 ) { if ((connfd = accept(listenfd, NULL, NULL)) < 0) { perror("fail to accept"); show_time(); break; }else{ printf("a connect from client accepted, counter = %d\n", counter++); show_time(); } recv(connfd, buf, N, 0); printf("recvd from client\n"); show_time(); send(connfd, "54321", 6, 0); printf("sent to client\n"); show_time(); close(connfd); } return 0; }
调试:
gcc -g client.c show_time.c -o client
gcc -g server.c show_time.c -o server
1. 打断点:
//break client.c:41
2. 跑server
3. 单步跑client,
当line47跑完 if (connect(sockfd, (SA *)&server_addr, sizeof(server_addr)) < 0) 的时候,
server打印“a connect from client accepted, counter = 0”
if ((connfd = accept(listenfd, NULL, NULL)) < 0) { perror("fail to accept"); show_time(); break; }else{ printf("a connect from client accepted, counter = %d\n", counter++); show_time(); }
当line53跑完 send(sockfd, command, strlen(command)+1, 0) 的时候,
server打印 ”recvd from client “
recv(connfd, buf, N, 0); printf("recvd from client\n"); show_time();
上面的实验说明了:
socket通信的几个函数接口之间的关系和时序。accept阻塞地等待client的connect接入;recv阻塞地等待client send的数据。