linux网络编程--服务器客户端(TCP实现)
2014-03-20 21:14
766 查看
linux下的一个服务器客户端的小程序,基于TCP的实现;服务器可以同时接受多个客户的接入,通过子进程处理客户请求,下面的例子中,服务器只将客户的IP和端口以及发送的信息显示,然后原样的将客户发送的信息发送给客户。客户端仅仅是输入信息以及显示收到的信息。
TCP通信的模式如下图,比较固定,对着图编代码就可以了:
服务器的main函数:
服务器处理客户请求:
客户端程序相对简单:
n_write 和 readline
这里有个错误,客户端的IP地址应该都是127.0.0.1,而端口号是内核随机分配的;上面的错误是在
服务器处理客户请求的函数str_echo 中,inet_ntoa()函数的参数传错了(上面已修正);
TCP通信的模式如下图,比较固定,对着图编代码就可以了:
服务器的main函数:
int main(int argc, char **argv) { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; //IPv4 address /*socket*/ listenfd = socket(AF_INET, SOCK_STREAM, 0);//创建一个TCP的socket if (-1 == listenfd) { perror("socket erro."); return -1; } /*bind*/ //首先初始化server的IP地址和端口,然后再与刚刚创建的socket绑定 bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET;//设置协议簇 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定本机的网卡 servaddr.sin_port = htons(1234);//绑定端口号,端口号可以随便取,大于1024就可以了 if (-1 == bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) { perror("bind error."); return -1; } /*listen*/ //到这里已经有了一个绑定了IP地址和端口号的socket了,但是这个socket是个主动的socket, //而作为server需要的是一个等待别的接入的被动的socket,所以得调用listen将这个socket设置为监听状态 //第二个参数表示服务器正在处理客户接入时的等待队列长度。 if (-1 == listen(listenfd, 10)) { perror("listen error."); return -1; } while (1) { clilen = sizeof(cliaddr); //调用accept等待客户的接入,同时accept会用第二个参数返回客户的IP地址, //通过第三个参数返回IP地址的实际大小,同时这个参数也是个值-结构参数,也就是 //在传递这个参数的时候,先给这个参数一个初始的值,然后函数中会根据具体的情况修改这个值, //所以这里传递的是指针。 //当客户接入后,将返回一个成功和客服连接的socket描述符,通过读写这个socket即可实现和客户的通信了 connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen); if (-1 == connfd) { if (EINTR == errno) continue; perror("accept error."); return -1; } //通过fock创建子进程来处理客户请求,这里只是显示客户的IP地址、端口号和发送的文字, //并将客户发送的文字回传给客户。 if (0 == (childpid=fork())) {//fock返回0 说明是子进程 //这里并没有关闭服务器的监听socket,只是将其引用计数减一,因为fork出来的子进程对父进程做了拷贝, //所以这个监听socket的引用计数将由1变成2,而内核只有在一个socket的引用计数变为0才回去关闭它 close(listenfd); //通过和客户连接的socket和客户通信 str_echo(connfd, cliaddr); return 0; } //父进程将和客户连接的socket的引用计数减一,同样并没有关闭这个socket close(connfd); } return 0; }
服务器处理客户请求:
#define BSIZE 100 void str_echo(int sockfd, struct sockaddr_in cliaddr) { ssize_t n; char buf[BSIZE]; while ((n=read(sockfd, buf, BSIZE))) {//读取客户发送的信息 buf = '\0'; printf("IP: %s, PORT: %d: %s\n", \ inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port), buf); //输出信息 n_write(sockfd, buf, n);//将受到的信息发送回客户,n_write的实现下面给出 } }
客户端程序相对简单:
int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; if (2 != argc) { printf("usage: ./client 127.0.0.1");// return -1; } /*socket*/ sockfd = socket(AF_INET, SOCK_STREAM, 0); //创建一个socket if (-1 == sockfd) { perror("socket error."); return -1; } /*connect*/ //首先初始化要连接的服务器的IP地址和端口号,然后调用connect去连接这个服务器 bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(1234); inet_pton(AF_INET, argv[1], &servaddr.sin_addr); if (-1 == connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) { perror("connect error."); return -1; } //连接成功后就可以通过这个socket来和服务器通信了 str_cli(stdin, sockfd); return 0; }
#define LSIZE 100 void str_cli(FILE *fp, int sockfd) { char sendline[LSIZE], recvline[LSIZE]; while (NULL != fgets(sendline, LSIZE, fp)) {//输入信息 n_write(sockfd, sendline, strlen(sendline));//发送给服务器 readline(sockfd, recvline, LSIZE);//从服务器读,函数实现下面给出 fputs(recvline, stdout);//打印读到的信息 } }
n_write 和 readline
/*write n bytes to fd*/ ssize_t n_write (int fd, void *buf, size_t n) { size_t nleft = n; ssize_t nwriten; char *bufp = buf; while (nleft > 0) { if ((nwriten = write (fd, bufp, nleft)) <= 0) { if (EINTR == errno) nwriten = 0; else return -1; } nleft -= nwriten; bufp += nwriten; } return n; } /*read line from fd*/ ssize_t readline (int fd, void *buf, size_t maxlen) { ssize_t n, rc; char c, *bufp; bufp = buf; for (n = 1; n < maxlen; n ++) { again: if (1 == (rc = read (fd, &c, 1))) { *bufp ++ = c; if ('\n' == c) break; /*newline is stored*/ } else if (rc == 0) { *bufp = 0; return (n - 1); /*EOF, n-1 bytes were read*/ } else { if (EINTR == errno) /*interrupt*/ goto again; return -1; /*Erro, set the errno by read ()*/ } } *bufp = 0; return n; }运行结果:
这里有个错误,客户端的IP地址应该都是127.0.0.1,而端口号是内核随机分配的;上面的错误是在
服务器处理客户请求的函数str_echo 中,inet_ntoa()函数的参数传错了(上面已修正);
相关文章推荐
- Linux 网络编程基础---------------客户端/服务器的简单实现
- Linux网络编程:客户端/服务器的简单实现
- Linux网络编程:TCP服务器(单进程多用户),使用select方法实现
- Linux网络编程 使用epoll实现一个高性能TCP Echo服务器
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- Linux网络编程——tcp并发服务器(epoll实现)
- C# 网络编程之Tcp实现客户端和服务器聊天
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- 网络编程资料总结(二)----Tcp多线程服务器和客户端的实现
- 【Linux网络编程】基于TCP单进程版本阻塞式客户端/服务器
- Linux下的C语言编程——简单实现tcp客户端和服务器
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- Linux 网络编程基础 客户端/服务器的简单实现
- Linux下网络socket编程——实现服务器(select)与多个客户端通信
- Linux网络编程 之 TCP 多线程的服务器和客户端同时收发数据
- TCP网络编程中多线程的客户端实现(linux下)