作者:2009级嵌入式
刘志卿
这是一个局域网通信程序,客户端通过连接服务器向局域网中的其它主机进行通讯.
服务器程序,用下面的命令直接编译,运行.
[root@localhost liu]# gcc server.c -o server
-------------------------------------------------------------------------------------*/
/*server.c*/
#include
#include
#include
#include
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE];
ssize_t n;
fd_set rset, allset;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
socklen_t cliaddr_len;
struct sockaddr_in cliaddr, servaddr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
Listen(listenfd, 20);
maxfd = listenfd; /* initialize */
maxi = -1; /* index into client[] array */
for (i = 0; i < FD_SETSIZE; i++)
client[i] = -1; /* -1 indicates available entry */
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
for (;;) {
rset = allset; /* structure assignment */
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0)
perr_exit("select error");
if (FD_ISSET(listenfd, &rset)) { /* new client connection */
cliaddr_len = sizeof(cliaddr);
connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));
for (i = 0; i < FD_SETSIZE; i++)
if (client[i] < 0) {
client[i] = connfd; /* save descriptor */
break;
}
if (i == FD_SETSIZE) {
fputs("too many clients\n", stderr);
exit(1);
}
FD_SET(connfd, &allset); /* add new descriptor to set */
if (connfd > maxfd)
maxfd = connfd; /* for select */
if (i > maxi)
maxi = i; /* max index in client[] array */
if (--nready == 0)
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++) { /* check all clients for data */
if ((sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset)) {
if ((n = Read(sockfd, buf, MAXLINE)) < 0) { //读取客户端发送的内容
/*connection closed by client */
Close(sockfd); //如果读取失败则关闭连接
FD_CLR(sockfd, &allset); //把这个文件描述符从连接中清除
client[i] = -1; //把客户端标志设为-1
} else {
int j;
for (j = 0; j <= maxi; j++) {
if (FD_ISSET(sockfd, &rset))
Write(client[j], buf, n); //把已读到的数据发送给每一个连接的客户端
}
}
if (--nready == 0)
break; /* no more readable descriptors */
}
}
}
}
/*------------------------------------------------------------------------------------
执行过程如下:
[root@localhost liu]# ./server
received from 127.0.0.1 at PORT 33679 //客户端连接上服务器
received from 127.0.0.1 at PORT 33680
-------------------------------------------------------------------------------------*/
注释:程序编译后直接运行,为了可以看到结果,可以打开多个终端进行测试,也可以在局域网内,两台以上的电脑进行测试.如果是局域网内多台电脑测试,则需要服务器端打开8000
端口.用下面的命令编译程序.
[root@localhost liu]# gcc client.c -o client
--------------------------------------------------------------------------------------------*/
/* client.c */
#include
#include
#include
#include
#include "wrap.h"
#include
#include
#include
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd, n;
pid_t pid;
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
pid = fork(); //分支为两个进程
if (pid > 0) { //父进程
while (fgets(buf, MAXLINE, stdin) != NULL) {
Write(sockfd, buf, strlen(buf)); //向客户端发送数据
}
}
if (pid == 0) { //子进程
int b_on = 1;
ioctl(sockfd, FIONBIO, &b_on);
for (;;)
if ((n = Read(sockfd, buf, MAXLINE)) > 0) //向服务器接收数据
Write(STDOUT_FILENO, buf, n); //把读到的数据写进标准输出
}
Close(sockfd);
return 0;
}
执行过程如下:
[root@localhost liu]# ./client
ni hao a //客户端向服务器发送数据
ni hao a //服务器端接收数据后发送给每一个已连接的客户端
hello
hello
hello!
hello!