Linux-socket编程-1对1和1对多聊天

xiaoxiao2025-06-16  11

1对1聊天

    通过select添加可读事件的监听实现。

    服务端:

#include "header.h" int main(void) { int listenfd = -1; int connfd = -1; struct sockaddr_in server, client; int on = 1; memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(8888); server.sin_addr.s_addr = htonl(INADDR_ANY); if (0 > (listenfd = socket(AF_INET, SOCK_STREAM, 0))) err_exit("socket"); setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (0 > bind(listenfd, (struct sockaddr *)&server, sizeof(server))) err_exit("bind"); listen(listenfd, 1024); printf("listen...\n"); memset(&client, 0, sizeof(client)); socklen_t len = sizeof(client); if (0 > (connfd = accept(listenfd, (struct sockaddr *)&client, &len))) err_exit("accept"); printf("client's ip is:%s, port is:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); char recv_buf[BUFSIZ]; char send_buf[BUFSIZ]; fd_set readfds; int maxfd = -1; int ret=-1; int i; while(1) { FD_ZERO(&readfds);//所有位置零 FD_SET(0, &readfds);//设置0比特位为1,用于发送数据消息通知 maxfd = maxfd > 0 ? maxfd : 0; FD_SET(connfd, &readfds);//设置connfd比特位为1,用于接受数据消息通知, maxfd = maxfd > connfd ? maxfd : connfd; if (0 > select(maxfd + 1, &readfds, NULL, NULL, NULL))//设置被监听的文件描述符的总数为maxfd + 1,readfds可读事件,且无限等待 err_exit("select"); for (i=0; i<=maxfd; i++) { if (FD_ISSET(i, &readfds)) //select返回后,用FD_ISSET测试给定位是否置位,通过获取那个bit位就知道是那个连接有数据 { if (i == 0)//有数据需要发送 { fgets(send_buf, sizeof(send_buf), stdin); if (0 > send(connfd, send_buf, strlen(send_buf) + 1, 0)) err_exit("send"); } else if (i == connfd)//有数据需要接收 { if (0 > (ret = recv(connfd, recv_buf, BUFSIZ, 0))) err_exit("recv"); else if (0 == ret) { printf("client quit!\n"); exit(0); } recv_buf[ret] = '\0'; printf("client: %s\n", recv_buf); } } } } close(listenfd); close(connfd); exit(0); }

    客户端:

#include "header.h" int main(void) { int connfd = -1; struct sockaddr_in server; memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(8888); server.sin_addr.s_addr = inet_addr("192.168.1.50"); if (0 > (connfd = socket(AF_INET, SOCK_STREAM, 0))) err_exit("socket"); if (0 > connect(connfd, (struct sockaddr *)&server, sizeof(server))) err_exit("connect"); printf("connect success!\n"); char send_buf[BUFSIZ]; char recv_buf[BUFSIZ]; int maxfd= -1; fd_set readfds; int ret=-1; int i; while(1) { FD_ZERO(&readfds); FD_SET(0, &readfds); maxfd = maxfd > 0 ? maxfd : 0; FD_SET(connfd, &readfds); maxfd = maxfd > connfd ? maxfd : connfd; if (0 > select(maxfd + 1, &readfds, NULL, NULL, NULL)) err_exit("select"); for (i=0; i<=maxfd; i++) { if (FD_ISSET(i, &readfds)) { if (0 == i) { fgets(send_buf, sizeof(send_buf), stdin); if (0 > send(connfd, send_buf, strlen(send_buf) + 1, 0)) err_exit("send"); } else if (connfd == i) { if (0 > (ret = recv(connfd, recv_buf, BUFSIZ, 0))) err_exit("recv"); else if (0 == ret) { printf("server quit!\n"); exit(0); } recv_buf[ret] = '\0'; printf("server: %s\n", recv_buf); } } } } close(connfd); exit(0); }

1对多聊天

    服务端:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/ip.h> #include <sys/select.h> struct peer_node { //链表结构体 int id; //id号 int connfd; //描述符 struct peer_node *next; //指针 }; static struct peer_node *head; //结构体指针 int server_init(short port) //server服务器初始化函数 { int sockfd; int on = 1; struct sockaddr_in self; if(0 > (sockfd = socket(AF_INET, SOCK_STREAM, 0))) { //创建套接字 fprintf(stderr, "socket : %s\n", strerror(errno)); return -errno; //返回出错 } if (0 > setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on))) { //允许重用本地址和端口 fprintf(stderr, "setsockopt : %s\n", strerror(errno)); exit(1); } memset(&self, 0, sizeof(self)); //初始化 self.sin_family = AF_INET; //ipv4 self.sin_port = htons(port); //端口 self.sin_addr.s_addr = INADDR_ANY; //本地ip if(0 > bind(sockfd, (struct sockaddr *)&self, sizeof(self))) { //绑定本地信息 fprintf(stderr,"socket bind error:%s\n",strerror(errno)); return -errno; } printf("listen...\n"); //启动监听 listen(sockfd,1024); return sockfd; //返回描述符 } int find_id_by_connfd(int connfd) //在链接里找id { struct peer_node *node; //节点 node = head->next; while(node) { if(node->connfd == connfd) return node->id; //返回id node = node->next; } return -1; } int show_message(int skfd) //打印信息 { char buf[1024]; struct sockaddr_in client; socklen_t len; int ret; len = sizeof(client); memset(&client, 0, sizeof(client)); ret = recv(skfd,buf,1023,0); //收 if(ret == 0) { return 0; } buf[ret] = 0; if(0 > getpeername(skfd, (struct sockaddr *)&client, &len)) { //或得信息 fprintf(stderr, "getpeername : %s\n", strerror(errno)); exit(1); } printf("message received from id:%d [%s:%d] : %s", find_id_by_connfd(skfd),inet_ntoa(client.sin_addr),ntohs(client.sin_port), buf); return 1; //打印 id ip 端口 信息 } int add_peerlist(int skfd) //把id从尾压入链表 { struct peer_node *node; //节点 static int id = 1; struct peer_node *tail; //尾 node = (struct peer_node *) malloc(sizeof(struct peer_node)); //开辟 堆 if(node == NULL) { perror("malloc"); return -1; } node->id = id; node->connfd = skfd; node->next = NULL; tail = head; while(tail->next) { tail = tail->next; } tail->next = node; id++; //id 自加 return (node->id); } int del_peerlist(int skfd) //删除 { struct peer_node *node; struct peer_node *tmp; int id; node = head; while(node->next->connfd != skfd) { node = node->next; } tmp = node->next; id = tmp->id; node->next = tmp->next; free(tmp); return id; } int show_peerlist(void) //打印id列表 { struct peer_node *node; struct sockaddr_in client; int ret; socklen_t len = sizeof(client); node = head->next; printf("=========================\n"); while(node) { ret = getpeername(node->connfd, (struct sockaddr *)&client,&len); if(ret < 0) { perror("getpeername"); } printf("%d:%s:%d\n",node->id, inet_ntoa(client.sin_addr),ntohs(client.sin_port)); //id ip 端口 node = node->next; } printf("=========================\n"); return 0; } int find_connfd_by_id(int id) // 找文件描述符 { struct peer_node *node; node = head->next; while(node) { if(node->id == id) return node->connfd; //返回 node = node->next; } return -1; } int init_peerlist(void) //初始化链表 { head = (struct peer_node *) malloc(sizeof(struct peer_node)); if (NULL == head) { fprintf(stderr, "malloc : %s\n", strerror(errno)); exit(1); } head->connfd = -1; head->next = NULL; return 0; } int send_message(void) //发送信息 { char buf[1024]; char *ptr = NULL; int skfd, id; char id_str[10]; //存放id fgets(buf,1024,stdin); if (!strncasecmp(buf, "quit", 4)) { printf("server close!\n"); exit(1); } if(0 == strncmp(buf,"list",4)) { //list 显示列表 show_peerlist(); return 0; } if(NULL == (ptr = strstr(buf,":"))) { //找出“:”位置指针 fprintf(stderr,"please usage \"ID:Message\" format!\n"); return 0; } memset(id_str, 0, 10); memcpy(id_str, buf, (ptr - buf)); //拷贝内存内容 把1:***** 字符1拷贝到 id_str if (0 >= (id = atoi(id_str))) { //转换成整数 fprintf(stderr, "the id is not valid!\n"); return -1; } skfd = find_connfd_by_id(id); if(skfd < 0) { fprintf(stderr,"Not found valid user!!!\n"); return -1; } if (0 > send(skfd, ptr+1, strlen(ptr + 1) + 1, 0)) { //发送:后面内容 fprintf(stderr,"send : %s\n", strerror(errno)); return -1; } return 0; } int main(int argc, char *argv[]) //主函数 { if (2 > argc) { //判断 fprintf(stderr, "Usage : %s + server portnumber\n", argv[0]); exit(1); } int listenfd; int newfd; int ret,maxfd,i,id; fd_set current_fds,bak_fds; char buf[1024]; init_peerlist(); short portnumber; if (0 >= (portnumber = atoi(argv[1]))) { //端口号输入 fprintf(stderr, "port number is invalid!\n"); exit(1); } listenfd = server_init(portnumber); //调用前面服务器函数 if(listenfd < 0) exit(-listenfd); printf("type \"list\" for the client list!\n"); FD_ZERO(&current_fds); FD_ZERO(&bak_fds); FD_SET(0, &current_fds); FD_SET(listenfd, &current_fds); maxfd = listenfd > 0 ? listenfd : 0; while(1) { bak_fds = current_fds; ret = select(maxfd+1, &bak_fds, NULL, NULL, NULL); //多路复用 if(ret < 0) { fprintf(stderr,"select error:%s\n",strerror(errno)); return errno; } for(i = 0; i <= maxfd; i++) { if(FD_ISSET(i, &bak_fds)) { if(0 == i) { send_message(); } else if (i == listenfd){ if (0 > (newfd = accept(listenfd, NULL, NULL))) { fprintf(stderr, "accept : %s\n", strerror(errno)); exit(1); } FD_SET(newfd, &current_fds); if(newfd > maxfd) maxfd = newfd; id = add_peerlist(newfd); snprintf(buf, sizeof(buf), "you id is %d\n", id); send(newfd, buf, strlen(buf) + 1, 0); printf("new connection : connfd is %d, id is %d\n", newfd, id); } else { ret = show_message(i); if(ret == 0) { close(i); FD_CLR(i, &current_fds); if(i == maxfd) maxfd--; printf("id : %d client quit!\n", del_peerlist(i)); } } } } } return 0; }

    客户端:

#include <stdio.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <resolv.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h> #define MAXBUF 1024 int main(int argc, char *argv[]) { int sockfd; socklen_t len; struct sockaddr_in dest; struct sockaddr_in self; char buffer[MAXBUF + 1]; fd_set rfds; struct timeval tv; int retval, maxfd = -1; if (argc < 2) { fprintf(stderr, "Usage : %s + server_port\n", argv[0]); exit(0); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "Socket : %s\n", strerror(errno)); exit(errno); } bzero(&dest, sizeof(dest)); dest.sin_family = AF_INET; if (0 > (dest.sin_port = htons(atoi(argv[1])))) { fprintf(stderr, "port number is wrong\n"); exit(1); } dest.sin_addr.s_addr = inet_addr("192.168.1.50"); if (0 > connect(sockfd, (struct sockaddr *) &dest, sizeof(dest))) { fprintf(stderr, "Connect : %s\n", strerror(errno)); exit(1); } printf("connect success!\n"); len = sizeof(self); if(0 > getsockname(sockfd, (struct sockaddr *)&self, &len)) { fprintf(stderr, "getsockname : %s\n", strerror(errno)); exit(1); } printf("Myself is %s:%d\n",inet_ntoa(self.sin_addr),ntohs(self.sin_port)); while (1) { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(sockfd, &rfds); if (sockfd > maxfd) maxfd = sockfd; tv.tv_sec = 1; tv.tv_usec = 0; retval = select(maxfd + 1, &rfds, NULL, NULL, &tv); if (retval == -1) { fprintf(stderr, "select : %s\n", strerror(errno)); break; } else if (retval == 0) { continue; } else { if (FD_ISSET(sockfd, &rfds)) { bzero(buffer, MAXBUF + 1); len = recv(sockfd, buffer, MAXBUF, 0); if (len > 0) printf("message received from server : %s",buffer); else{ if (len < 0) fprintf(stderr, "recv : %s\n", strerror(errno)); else printf("server close!\n"); break; } } else if(FD_ISSET(0, &rfds)) { bzero(buffer, MAXBUF + 1); fgets(buffer, MAXBUF, stdin); if (!strncasecmp(buffer, "quit", 4)) { printf("client close!\n"); break; } if ( 0 > send(sockfd, buffer, strlen(buffer)+1, 0)) { fprintf(stderr, "send : %s\n", strerror(errno)); //break; } } } } close(sockfd); return 0; }

   使用方法:Usage : ./server + server portnumber;./client + server portnumber

 

转载请注明原文地址: https://www.6miu.com/read-5031954.html

最新回复(0)