




已阅读5页,还剩22页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
计算机学院 网络13卓越班 郑仙玉 学号:201300824401上机四:Linux网络编程一上机目标:(1) 掌握“TCP套接字”编程(2) 掌握“UDP套接字”编程上机实例:(1) 编写TCP客户端和服务器端程序服务器端:能够处理多并发(每个子进程处理一个客户端连接;),实现信息回射(echo)客户端:实现信息发送和显示实验步骤:1) 先建立文件夹TCP,并在TCP文件夹中建立client文件夹和service文件夹:图4-1、TCP文件中的保含文件2) 在service文件夹内建立service.cpp和makefile文件:图4-2、列出service文件夹中的文件 3)在client文件夹内建立client.cpp和Makefile文件:图4-3、列出client文件夹中的文件4) service文件夹中的makefile文件内容:图4-4、service的makefile内容5) client文件夹中的Makefile文件内容:图4-5、client的Makefile内容6) 在终端中service的运行过程:图4-6、service可执行文件的生成7) 在终端中client的运行过程:图4-7、client可执行文件的生成8) 客户机和服务器建立连接截图如下:图4-8、运行service图4-9、运行client9) 客户机向服务器发送信息:图4-10、客户机发送消息图4-11、服务器接收到消息,并回应10) 代码服务器端代码:#include #include #include #include #include #include #include #include #include #include #define SERV_PORT 8888#define SERV_IP 127.0.0.1 /本地回环接口#define LIST 20 /服务器最大接受连接#define MAX_FD 10 /FD_SET支持描述符数量int main(void) int sockfd; int err; int i; int connfd; int fd_allMAX_FD; /保存所有描述符,用于select调用后,判断哪个可读/下面两个备份原因是select调用后,会发生变化,再次调用select前,需要重新赋值 fd_set fd_read; /FD_SET数据备份 fd_set fd_select; /用于select struct timeval timeout; /超时时间备份 struct timeval timeout_select; /用于select struct sockaddr_in serv_addr; /服务器地址 struct sockaddr_in cli_addr; /客户端地址 socklen_t serv_len; socklen_t cli_len; /超时时间设置 timeout.tv_sec = 10; timeout.tv_usec = 0; sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd 0) perror(fail to socket); exit(1); memset(&serv_addr, 0, sizeof(serv_addr); memset(&cli_addr, 0, sizeof(cli_addr); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(SERV_PORT); serv_addr.sin_addr.s_addr = inet_addr(SERV_IP); serv_len = sizeof(serv_addr); err = bind(sockfd, (struct sockaddr *)&serv_addr, serv_len); if(err 0) perror(fail to bind); exit(1); err = listen(sockfd, LIST); if(err 0) perror(fail to listen); exit(1); /初始化fd_all数组 memset(&fd_all, -1, sizeof(fd_all); fd_all0 = sockfd; /第一个为监听套接字 FD_ZERO(&fd_read); FD_SET(sockfd, &fd_read); /将监听套接字加入fd_set char buf1024; /读写缓冲区 int num; int maxfd; maxfd = fd_all0; /监听的最大套接字 while(1) /每次都需要重新赋值 fd_select = fd_read; timeout_select = timeout;/ err = select(maxfd+1, &fd_select, NULL, NULL, NULL); err = select(maxfd+1, &fd_select, NULL, NULL, (struct timeval *)&timeout_select); if(err 0) perror(fail to select); exit(1); if(err = 0) printf(timeoutn); /检测监听套接字是否可读 if(FD_ISSET(sockfd, &fd_select) /可读,证明有新客户端连接服务器 cli_len = sizeof(cli_addr); connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_len); if(connfd 0) perror(fail to accept); exit(1); /将新连接套接字加入fd_all及fd_read for(i=0; iMAX_FD; i+) if(fd_alli != -1) continue; else fd_alli = connfd; printf(client fd_all%d joinn, i); break; FD_SET(connfd, &fd_read); if(maxfd connfd) maxfd = connfd; /更新maxfd /从1开始查看连接套接字是否可读,因为上面已经处理过0(sockfd) for(i=1; i 0) if(strncmp(exit, buf, 4) = 0) /客户端退出,关闭套接字,并从监听集合清除 printf(client:fd_all%d exitn, i); FD_CLR(fd_alli, &fd_read); close(fd_alli); fd_alli = -1; continue; /收到 客户端数据并打印 bufnum = 0; printf(receive buf from client fd_all%d is: %sn, i, buf); /回复客户端 num = write(fd_alli, ok, sizeof(ok); if(num 0) perror(fail to write ); exit(1); else printf(send replyn); else /printf(no datan); return 0;客户端代码:#include #include #include #include #include #include #include #include #include #define SERV_PORT 8888#define SERV_IP 127.0.0.1int main(void) int sockfd; int err; int connfd; struct sockaddr_in serv_addr; struct sockaddr_in cli_addr; socklen_t serv_len; socklen_t cli_len; sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd 0) perror(fail to socket); exit(1); memset(&serv_addr, 0, sizeof(serv_addr); memset(&cli_addr, 0, sizeof(cli_addr); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(SERV_PORT); serv_addr.sin_addr.s_addr = inet_addr(SERV_IP); serv_len = sizeof(serv_addr);/客户端不需要绑定,直接连接即可 err = connect(sockfd, (struct sockaddr *)&serv_addr, serv_len); if(err 0) /exit代表退出 if(strncmp(exit, buf, 4) = 0) write(sockfd, buf, num); break; write(sockfd, buf, num); num = read(sockfd, buf, 1024); if(num 0) bufnum = 0; printf(server reply: %sn, buf); else printf(error to readn); close(sockfd); return 0;(2) 编写UDP客户端和服务器程序(简单聊天程序)服务器端:能够处理客户端登录、用户列表管理客户端:实现客户端之间的公聊和私聊上机要求:(1) 编写源程序 (2) 编写Makefile文件(3) 编译、运行、调试程序实验步骤:. 创建UDP文件夹,中包含chat_public文件夹和chat_private文件夹图4-12、UDP中的文件夹. 公聊:1) chat_public文件夹中所包含的文件:图4-13、chat_public中的文件2) chat_public中Makefile文件的内容:图4-14、公聊的Makefile内容3) 进入chat_public后,输入make:图4-15、执行make前和执行make后的界面4) 在登录3个人时,服务器终端的显示如下:图4-16、服务器处理处理客户端登录、用户列表管理5) 客户端1、2、3登录、取名如下:客户端1:名为zhengxianyu客户端2:名为xianyu客户端3:名为zheng6) 客户端之间发送聊天消息:客户端1向客户端2发送消息客户端2接收到客户端1的消息客户端2向客户端3发送消息客户端3接收到客户端2的消息客户端3向客户端1发送消息客户端1接收到客户端3的消息7) 源代码:Chatsrv.cpp的代码:#include #include #include #include #include #include #include #include #include #include #include #include pub.h#define ERR_EXIT(m) do perror(m); exit(EXIT_FAILURE); while(0)/ 聊天室成员列表USER_LIST client_list;void do_login(MESSAGE& msg, int sock, struct sockaddr_in *cliaddr);void do_logout(MESSAGE& msg, int sock, struct sockaddr_in *cliaddr);void do_sendlist(int sock, struct sockaddr_in *cliaddr);void chat_srv(int sock)struct sockaddr_in cliaddr;socklen_t clilen;int n;MESSAGE msg;while (1)memset(&msg, 0, sizeof(msg);clilen = sizeof(cliaddr);n = recvfrom(sock, &msg, sizeof(msg), 0, (struct sockaddr *)&cliaddr, &clilen);if (n sin_addr.s_addr;user.port = cliaddr-sin_port;/* 查找用户 */USER_LIST:iterator it;for (it=client_list.begin(); it != client_list.end(); +it)if (strcmp(it-username,msg.body) = 0)break;if (it = client_list.end()/* 没找到用户 */printf(has a user login : %s %s:%dn, msg.body, inet_ntoa(cliaddr-sin_addr), ntohs(cliaddr-sin_port);client_list.push_back(user);/ 登录成功应答MESSAGE reply_msg;memset(&reply_msg, 0, sizeof(reply_msg);reply_msg.cmd = htonl(S2C_LOGIN_OK);sendto(sock, &reply_msg, sizeof(msg), 0, (struct sockaddr *)cliaddr, sizeof(struct sockaddr_in);int count = htonl(int)client_list.size();/ 发送在线人数sendto(sock, &count, sizeof(int), 0, (struct sockaddr *)cliaddr, sizeof(struct sockaddr_in);printf(sending user list information to: %s %s:%dn, msg.body, inet_ntoa(cliaddr-sin_addr), ntohs(cliaddr-sin_port);/ 发送在线列表for (it=client_list.begin(); it != client_list.end(); +it)sendto(sock, &*it, sizeof(USER_INFO), 0, (struct sockaddr *)cliaddr, sizeof(struct sockaddr_in);/ 向其他用户通知有新用户登录for (it=client_list.begin(); it != client_list.end(); +it)if (strcmp(it-username,msg.body) = 0)continue;struct sockaddr_in peeraddr;memset(&peeraddr, 0, sizeof(peeraddr);peeraddr.sin_family = AF_INET;peeraddr.sin_port = it-port;peeraddr.sin_addr.s_addr = it-ip;msg.cmd = htonl(S2C_SOMEONE_LOGIN);memcpy(msg.body, &user, sizeof(user);if (sendto(sock, &msg, sizeof(msg), 0, (struct sockaddr *)&peeraddr, sizeof(peeraddr) 0)ERR_EXIT(sendto);else/* 找到用户 */printf(user %s has already loginedn, msg.body);MESSAGE reply_msg;memset(&reply_msg, 0, sizeof(reply_msg);reply_msg.cmd = htonl(S2C_ALREADY_LOGINED);sendto(sock, &reply_msg, sizeof(reply_msg), 0, (struct sockaddr *)cliaddr, sizeof(struct sockaddr_in);void do_logout(MESSAGE& msg, int sock, struct sockaddr_in *cliaddr)printf(has a user logout : %s %s:%dn, msg.body, inet_ntoa(cliaddr-sin_addr), ntohs(cliaddr-sin_port);USER_LIST:iterator it;for (it=client_list.begin(); it != client_list.end(); +it)if (strcmp(it-username,msg.body) = 0)break;if (it != client_list.end()client_list.erase(it);/ 向其他用户通知有用户登出for (it=client_list.begin(); it != client_list.end(); +it)if (strcmp(it-username,msg.body) = 0)continue;struct sockaddr_in peeraddr;memset(&peeraddr, 0, sizeof(peeraddr);peeraddr.sin_family = AF_INET;peeraddr.sin_port = it-port;peeraddr.sin_addr.s_addr = it-ip;msg.cmd = htonl(S2C_SOMEONE_LOGOUT);if (sendto(sock, &msg, sizeof(msg), 0, (struct sockaddr *)&peeraddr, sizeof(peeraddr) 0)ERR_EXIT(sendto);void do_sendlist(int sock, struct sockaddr_in *cliaddr)MESSAGE msg;msg.cmd = htonl(S2C_ONLINE_USER);sendto(sock, (const char*)&msg, sizeof(msg), 0, (struct sockaddr *)cliaddr, sizeof(struct sockaddr_in);int count = htonl(int)client_list.size();/* 发送在线用户数 */sendto(sock, (const char*)&count, sizeof(int), 0, (struct sockaddr *)cliaddr, sizeof(struct sockaddr_in);/* 发送在线用户列表 */for (USER_LIST:iterator it=client_list.begin(); it != client_list.end(); +it)sendto(sock, &*it, sizeof(USER_INFO), 0, (struct sockaddr *)cliaddr, sizeof(struct sockaddr_in);int main(void)int sock;if (sock = socket(PF_INET, SOCK_DGRAM, 0) 0)ERR_EXIT(socket);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);if (bind(sock, (struct sockaddr*)&servaddr, sizeof(servaddr) 0)ERR_EXIT(bind);chat_srv(sock);return 0;Chatcli.cpp的代码:#include #include #include #include #include #include #include #include #include #include #include pub.h#define ERR_EXIT(m) do perror(m); exit(EXIT_FAILURE); while(0)/ 当前用户名char username16;/ 聊天室成员列表USER_LIST client_list;void do_someone_login(MESSAGE& msg);void do_someone_logout(MESSAGE& msg);void do_getlist();void do_chat();void parse_cmd(char* cmdline, int sock, struct sockaddr_in *servaddr);bool sendmsgto(int sock, char* username, char* msg);void parse_cmd(char* cmdline, int sock, struct sockaddr_in *servaddr)char cmd10=0;char *p;p = strchr(cmdline, );if (p != NULL)*p = 0;strcpy(cmd, cmdline);if (strcmp(cmd, exit) = 0)MESSAGE msg;memset(&msg,0,sizeof(msg);msg.cmd = htonl(C2S_LOGOUT);strcpy(msg.body, username);if (sendto(sock, &msg, sizeof(msg), 0, (struct sockaddr *)servaddr, sizeof(struct sockaddr_in) 0)ERR_EXIT(sendto);printf(user %s has logout servern, username);exit(EXIT_SUCCESS);else if (strcmp(cmd, send) = 0)char peername16=0;char msgMSG_LEN=0;/* send user msg */* p p2 */while (*p+ = ) ;char *p2;p2 = strchr(p, );if (p2 = NULL)printf(bad commandn);printf(nCommands are:n);printf(send username msgn);printf(listn);printf(exitn);printf(n);return;*p2 = 0;strcpy(peername, p);while (*p2+ = ) ;strcpy(msg, p2);sendmsgto(sock, peername, msg);else if (strcmp(cmd, list) = 0)MESSAGE msg;memset(&msg, 0, sizeof(msg);msg.cmd = htonl(C2S_ONLINE_USER);if (sendto(sock, &msg, sizeof(msg), 0, (struct sockaddr *)servaddr, sizeof(struct sockaddr_in) username,name) = 0)break;if (it = client_list.end()printf(user %s has not logined servern, name);return false;MESSAGE m;memset(&m,0,sizeof(m);m.cmd = htonl(C2C_CHAT);CHAT_MSG cm;strcpy(cm.username, username);strcpy(cm.msg, msg);memcpy(m.body, &cm, sizeof(cm);/strcpy(m.body,msg);struct sockaddr_inpeeraddr;memset(&peeraddr,0,sizeof(peeraddr);peeraddr.sin_family = AF_INET;peeraddr.sin_addr.s_addr = it-ip;peeraddr.sin_port = it-port;in_addr tmp;tmp.s_addr = it-ip;printf(sending message %s to user %s %s:%dn, msg, name, inet_ntoa(tmp), ntohs(it-port);sendto(sock, (const char*)&m, sizeof(m), 0, (struct sockaddr *)&peeraddr, sizeof(peeraddr);return true;void do_getlist(int sock)int count;recvfrom(sock, &count, sizeof(int), 0, NULL, NULL);printf(has %d users logined servern, ntohl(count);client_list.clear();int n = ntohl(count);for (int i=0; in; i+)USER_INFO user;recvfrom(sock,&user, sizeof(USER_INFO), 0, NULL, NULL);client_list.push_back(user);in_addr tmp;tmp.s_addr = user.ip;printf(%s %s:%dn, user.username, inet_ntoa(tmp), ntohs(user.port);void do_someone_login(MESSAGE& msg)USER_INFO *user = (USER_INFO*)msg.body;in_addr tmp;tmp.s_addr = user-ip;print
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论