Linux网络编程之聊天程序(TCP协议之select)

服务器端:server.c

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/time.h>

#include <sys/types.h>

#define MAXBUF 1024

int main(int argc, char **argv)

{

int sockfd, new_fd;

socklen_t len;

struct sockaddr_in my_addr, their_addr;

unsigned int myport, lisnum;

char buf[MAXBUF + 1];

fd_set rfds;

struct timeval tv;

int retval, maxfd = -1;

if (argv[2])

myport = atoi(argv[2]);       /* 将命令行字符串转换为整数。用于端口 */

else

myport = 8888;                           /* 设置默认端口 */

if (argv[3])

lisnum = atoi(argv[3]);                     /* 监听队列大小 */

else

lisnum = 2;

if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {             /* 创建socket对象 */

perror("socket");

exit(EXIT_FAILURE);

}

bzero(&my_addr, sizeof(my_addr));

my_addr.sin_family = PF_INET;                /* 地址协议 */

my_addr.sin_port = htons(myport);             /* 地址端口 */

if (argv[1])

my_addr.sin_addr.s_addr = inet_addr(argv[1]);

else

my_addr.sin_addr.s_addr = INADDR_ANY;                    /* 否则默认本机随意地址 */

if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) { /* 绑定地址信息 */

perror("bind");

exit(EXIT_FAILURE);

}

if (listen(sockfd, lisnum) == -1) { 
/* 监听网络 ,最大队列数是lisnum*/

perror("listen");

exit(EXIT_FAILURE);

}

while (1)

{

printf ("\n----wait for new connect\n");

len = sizeof(struct sockaddr);

if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1) {

/* 堵塞等待连接。连接成功返回新的socket描写叙述符,their_addr存储client的sockaddr 地址信息

perror("accept");

exit(errno);

} else

printf("server: got connection from %s, port %d, socket %d\n",

inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);

while (1)

{

FD_ZERO(&rfds);    
/* 清零rfds集合 */

FD_SET(0, &rfds);  
/* 把标准输入加入rfds集合 */

FD_SET(new_fd, &rfds);                 /*
把new_fd加入rfds集合 */

maxfd = new_fd;

tv.tv_sec = 1;

tv.tv_usec = 0;

retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);    /*
maxfd + 1监听的最大值加一 */

if (retval == -1)

{

perror("select");

exit(EXIT_FAILURE);

} else if (retval == 0) {

continue;

}

else

{

if (FD_ISSET(0, &rfds))                        /* 假设是标准输入可读 */

{

bzero(buf, MAXBUF + 1);

fgets(buf, MAXBUF, stdin);

if (!strncasecmp(buf, "quit", 4)) {

printf("i will quit!\n");

break;

}

len = send(new_fd, buf, strlen(buf) - 1, 0);

if (len > 0)

printf ("send successful,%d byte send!\n",len);

else {

printf("send failure!");

break;

}

}

if (FD_ISSET(new_fd, &rfds))             /* 假设是new_fd可读 */

{

bzero(buf, MAXBUF + 1);

len = recv(new_fd, buf, MAXBUF, 0);

if (len > 0)

printf ("recv success :‘%s‘,%dbyte recv\n", buf, len);

else

{

if (len < 0)

printf("recv failure\n");

else

{

printf("the ohter one end ,quit\n");

break;

}

}

}

}

}

close(new_fd);

printf("need othe connecdt (no->quit)");

fflush(stdout);

bzero(buf, MAXBUF + 1);

fgets(buf, MAXBUF, stdin);

if (!strncasecmp(buf, "no", 2))

{

printf("quit!\n");

break;

}

}

close(sockfd);

return 0;

}

客户端程序:client.c

#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, len;

struct sockaddr_in dest;

char buffer[MAXBUF + 1];

fd_set rfds;

struct timeval tv;

int retval, maxfd = -1;

if (argc != 3)

{

printf("argv format errno,pls:\n\t\t%s IP port\n",argv[0], argv[0]);

exit(EXIT_FAILURE);

}

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)

{

perror("Socket");

exit(EXIT_FAILURE);

}

bzero(&dest, sizeof(dest));

dest.sin_family = AF_INET;

dest.sin_port = htons(atoi(argv[2]));

if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)

{

perror(argv[1]);

exit(EXIT_FAILURE);

}

if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)

{

perror("Connect ");

exit(EXIT_FAILURE);

}

printf("\nget ready pls chat\n");

while (1)

{

FD_ZERO(&rfds);

FD_SET(0, &rfds);

FD_SET(sockfd, &rfds);

maxfd = sockfd;

tv.tv_sec = 1;

tv.tv_usec = 0;

retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);

if (retval == -1)

{

printf("select %s", 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 ("recv message:‘%s‘,%d byte recv\n",buffer, len);

else

{

if (len < 0)

printf ("message recv failure\n");

else

{

printf("the othe quit ,quit\n");

break;

}

}

}

if (FD_ISSET(0, &rfds))

{

bzero(buffer, MAXBUF + 1);

fgets(buffer, MAXBUF, stdin);

if (!strncasecmp(buffer, "quit", 4)) {

printf("i will quit\n");

break;

}

len = send(sockfd, buffer, strlen(buffer) - 1, 0);

if (len < 0) {

printf ("message send failure");

break;

} else

printf

("send success,%d byte send\n",len);

}

}

}

close(sockfd);

return 0;

}

測试方法例如以下:

gcc server.c -o server

gcc client.c -o client

./server 172.16.148.114  8888       /* 一个终端下。172.16.148.114是我虚拟机的IP地址*/

./client 172.16.148.114  8888      /*另外 一个终端下 */

select函数不会使用的參考这篇文章:http://blog.csdn.net/qq_21792169/article/details/50450360

时间: 2024-10-10 20:21:38

Linux网络编程之聊天程序(TCP协议之select)的相关文章

嵌入式 Linux网络编程(二)——TCP编程模型

嵌入式 Linux网络编程(二)--TCP编程模型 一.TCP编程模型 TCP编程的一般模型如下图: TCP编程模型分为客户端和服务器端编程,两者编程流程如下: TCP服务器端编程流程: A.创建套接字: B.绑定套接字: C.设置套接字为监听模式,进入被动接受连接状态: D.接受请求,建立连接: E.读写数据: F.终止连接. TCP客户端编程流程: A.创建套接字: B.与远程服务器建立连接: C.读写数据: D.终止连接. 二.TCP迭代服务器编程模型 TCP循环服务器接受一个客户端的连接

Linux网络编程 五种I/O 模式及select、epoll方法的理解

Linux网络编程 五种I/O 模式及select.epoll方法的理解 web优化必须了解的原理之I/o的五种模型和web的三种工作模式 五种I/O 模式--阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/OLinux网络编程 五种I/O 模式及select.epoll方法的理解

Linux网络编程——连接和面向连接的协议之间没有区别

网络编程中最重要的概念就是连接取向(connection-oriented)和无连接(connectionless)协议.虽然本质.两者之间的区别是不难理解,编程的人来说,却是个非常easy混淆的问题. 这个问题与上下文有些关联:非常显然.假设两台计算机要进行通信,就必须以某种形式"连接"起来.那"无连接通信"又是什么意思呢? 答案是:面向连接和无连接指的都是协议. 也就是说,这些术语指的并非物理介质本身.而是用来说明怎样在物理介质上数据传输的.面向连接和无连接协议

【Linux网络编程】无连接和面向连接协议的区别

网络编程中最基本的概念就是面向连接(connection-oriented)和无连接(connectionless)协议.尽管本质上来说,两者之间的区别并不难理解,但对那些刚刚开始进行网络编程的人来说,却是个很容易混淆的问题.这个问题与上下文有些关联:很显然,如果两台计算机要进行通信,就必须以某种形式"连接"起来,那"无连接通信"又是什么意思呢? 答案是:面向连接和无连接指的都是协议.也就是说,这些术语指的并不是物理介质本身,而是用来说明如何在物理介质上传输数据的.

【Linux网络编程】因特网的IP协议是不可靠无连接的,那为什么当初不直接把它设计为可靠的?

因特网使用的IP协议是无连接的,因此其传输是不可靠的.这样容易使人们感到因特网很不可靠,那为什么当初不直接把它设计为可靠的? 先打一个比方.邮局寄送的平信很像无连接的IP数据报.每封平信可能走不同的传送路径,同时平信也不保证不丢失.当我们发现收信人没有收到寄出的平信时,去找邮局索赔是没有用的.邮局会说:"平信不保证不丢失.怕丢失就请你寄挂号信".但是大家并不会将所有的信件都用挂号方式邮寄,这是因为邮局从来不会随意地将平信丢弃,而丢失平信的概率并不大,况且寄挂号信要多花些钱,还要去邮局排

网络编程(二)——TCP协议、socket

TCP协议与socket套接字 一.TCP协议 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包不必再分割. 2.(1)三次握手建链接(2)四次挥手断开链接(3)tcp协议的状态(4)syn洪水攻击与半连接池 3.(1)三次握手建立链接.四次挥手断开链接(各种状态) (2)syn洪水攻击与半连接池 syn洪水攻击:就是让服务器资源耗尽,无法提供正常的服务,间接地拒绝 半连接池:暂时存放请求,用

Java网络编程--简单聊天程序

背景 毕业设计前的练手,学校小比赛中的一个题目. 开发环境 Java(eclipse)+Mysql 简介 使用Java+Mysql开发以个简单的聊天工具,在本次项目中实现了: 1. 用户登录(客户端至服务器) 2. 登录服务器的用户可以公共聊天 3. 用户间可以实现私密聊天 下一次版本更新 实现同一账号只能一地登录. 界面 登录界面: 聊天主窗口: 私聊窗口:

linux网络编程基础--(转自网络)

转自 http://www.cnblogs.com/MyLove-Summer/p/5215287.html Linux下的网络编程指的是socket套接字编程,入门比较简单. 1. socket套接字介绍 socket机制其实就是包括socket, bind, listen, connect, accept等函数的方法,其通过指定的函数实现不同的协议(IP4,IP6等)的数据在不同层之间的传输和获取等处理.其实个人理解socket就是处于应用层和TCP/IP协议之间的一个中间层,具体的数据分析

Linux 网络编程系列教程

01.Linux网络编程1--网络协议入门 02.Linux网络编程2--无连接和面向连接协议的区别 03.Linux网络编程3--编程准备:字节序.地址转换 04.Linux网络编程4--UDP编程 05.Linux网络编程5--广播 06.Linux网络编程7--多播 08.Linux网络编程8--TCP编程 09.Linux网络编程9--并发服务器 10.Linux网络编程10--原始套接字能干什么? 11.Linux网络编程11--原始套接字编程 12.Linux网络编程12--原始套接