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
Linux网络编程之聊天程序(TCP协议之select)的更多相关文章
- 网络编程应用:基于TCP协议【实现一个聊天程序】
要求: 基于TCP协议实现一个聊天程序,客户端发送一条数据,服务器端发送一条数据 客户端代码: package Homework1; import java.io.IOException; impor ...
- Linux网络编程——连接和面向连接的协议之间没有区别
网络编程中最重要的概念就是连接取向(connection-oriented)和无连接(connectionless)协议.虽然本质.两者之间的区别是不难理解,编程的人来说,却是个非常easy混淆的问题 ...
- Java网络编程——UDP聊天程序
UDP简介 UDP协议的全称是用户数据报,在网络中它与TCP协议一样用于处理数据报.在OSI模型中,UDP位于第四层--传输层,处于IP协议额上一层.UDP有不提供数据报分组.组装以及不能对数据报排序 ...
- UNIX/Linux网络编程基础:图解TCP/IP协议栈
目录 1.主机到网络层协议:以太网协议 2.IP协议 3.网际控制报文协议(ICMP) 4.传输控制协议(TCP) 5.用户数据报文协议(UDP) 6.流控制传输协议(SCTP) 7.地址解析协议(A ...
- 网络编程(二)--TCP协议、基于tcp协议的套接字socket
一.TCP协议(Transmission Control Protocol 传输控制协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会 ...
- python网络编程——使用UDP、TCP协议收发信息
UDP UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送. UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内. UDP ...
- 网络编程(二)——TCP协议、基于tcp协议的套接字socket
TCP协议与基于tcp协议的套接字socket 一.TCP协议(流式协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的 ...
- 网络编程应用:基于TCP协议【实现对象传输】--练习
要求: 基于TCP协议实现,客服端向服务器发送一个对象 服务器接受并显示用户信息 ,同时返回给客户端 "数据已收到" 建一个Student类,属性:name age Student ...
- 网络编程应用:基于TCP协议【实现文件上传】--练习
要求: 基于TCP协议实现一个向服务器端上传文件的功能 客户端代码: package Homework2; import java.io.File; import java.io.FileInputS ...
随机推荐
- NOIP2013 D1 T3 货车运输
好吧,遇上这种题,作为蒟蒻的我第一个想到的就是怎么打暴力,然而暴力都打不好QAQ!!!于是只能等教练讲解以后,然后在大犇的指导下终于做出来了. 对了,,好像还,没上题....: 题目描述 A 国有 n ...
- Codeforces 196 E. Tricky and Cleve Password
\(>Codeforces \space 196\ E. Tricky\ and\ Cleve\ Password<\) 题目大意 : 给出一个有 \(n\) 个结点,\(m\) 条边的连 ...
- div块元素垂直水平居中方法总结
1.已知块级元素的宽和高,使用绝对定位+外边距设定水平垂直居中. 父元素position:relative,子元素position:absolute;top:50%;left:50%;margin-t ...
- poj 1984 并查集
题目意思是一个图中,只有上下左右四个方向的边.给出这样的一些边, 求任意指定的2个节点之间的距离. 就是看不懂,怎么破 /* POJ 1984 并查集 */ #include <stdio.h& ...
- spring ioc 理解
springIOC 作用 springIOC 是sprig的特性.称作控制反转.将对象的创建,初始化,销毁,交给spring容器管理. 原理 在spring容器启动的时候,通过反射的方式,主动加载(或 ...
- 如何解决IIS7上传文件大小限制,.NET 上传文件后 找不到目录解决
IIS7 默认文件上传大小是30M,那么超过30M的文件就无法上传了,那么就需要对IIS的配置文件进行修改. 在实际应用中往往会出现上传文件太大,无法上传的情况,那是因为IIS对上传文件大小有限制,I ...
- FreeRTOS介绍与移植
http://andyhuzhill.github.io/freertos/2013/07/30/freertostransplant/ 最近在看一个实时嵌入式操作系统————FreeRTOS, 为什 ...
- Digital Adjustment of DC-DC Converter Output Voltage 电阻选择
- set bin 集合
set: create table rr(zz char(4));create table test5 (rr set('美丽','态度好','温柔','善良'));insert into test5 ...
- Caliburn.Micro对目录结构的要求
Caliburn.Micro对MVVM目录结构的要求判定规则是如下正则表达式: (?<nsbefore>([A-Za-z_]\w*\.)*)(?<subns>ViewModel ...