Socket网络编程--聊天程序(2)
上一节简单如何通过Socket创建一个连接,然后进行通信。只是每个人只能说一句话。而且还是必须说完才会接收到信息,总之是很不方便的事情。所以这一小节我们将对上一次的程序进行修改,修改成每个人可以多说话,主要是通过Linux下多进程fork实现的。
一对一,server和client是每个人都可以多说几句话
由于控制台度数据的函数fgets是阻塞函数,要每个人都可以多说话,这里我使用的是读取和发送都在不同的进程里面,使之互相没有影响。
fork函数
#include <unistd.h>
pid_t fork(void); //返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1
client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h> //for gethostbyname
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> #define MAX_BUF 4096
#define SERVER_PORT 12138 int main(int argc,char *argv[])
{
int sockfd;//socket
char sendBuf[MAX_BUF],recvBuf[MAX_BUF];
int sendSize,recvSize;//用于记录记录发送和接收到数据的大小
struct hostent * host;
struct sockaddr_in servAddr;
char username[];
char * p;
int pid; if(argc != )
{
perror("use: ./client [hostname] [username]");
exit(-);
}
p=username;
strcpy(p,argv[]);
printf("username:%s\n",username);
host=gethostbyname(argv[]);
if(host==NULL)
{
perror("fail to get host by name.");
exit(-);
}
printf("Success to get host by name ...\n"); //创建socket
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-)
{
perror("fail to establish a socket");
exit();
}
printf("Success to establish a socket...\n"); /*init sockaddr_in*/
servAddr.sin_family=AF_INET;
servAddr.sin_port=htons(SERVER_PORT);
servAddr.sin_addr=*((struct in_addr *)host->h_addr);
bzero(&(servAddr.sin_zero),); /*connect the socket*/
if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-)
{
perror("fail to connect the socket");
exit();
}
printf("Success to connect the socket...\n"); //send-recv 一些返回指没有判断,具体可以看server.c
if((pid=fork())<)
{
perror("fork error\n");
}
else if(pid>)/*child*/
{
while()
{
fgets(sendBuf,MAX_BUF,stdin);
send(sockfd,sendBuf,strlen(sendBuf),);
memset(sendBuf,,sizeof(sendBuf));
}
}
else
{
while()
{
recv(sockfd,recvBuf,MAX_BUF,);
printf("Server:%s\n",recvBuf);
memset(recvBuf,,sizeof(recvBuf));
}
} return ;
}
server.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h> #define SERVER_PORT 12138
#define BACKLOG 20
#define MAX_CON_NO 10
#define MAX_DATA_SIZE 4096 int main(int argc,char *argv[])
{
struct sockaddr_in serverSockaddr,clientSockaddr;
char sendBuf[MAX_DATA_SIZE],recvBuf[MAX_DATA_SIZE];
int sendSize,recvSize;
int sockfd,clientfd;
int on=;
int sinSize=;
char username[];
int pid; if(argc != )
{
printf("usage: ./server [username]\n");
exit();
}
strcpy(username,argv[]);
printf("username:%s\n",username); /*establish a socket*/
if((sockfd = socket(AF_INET,SOCK_STREAM,))==-)
{
perror("fail to establish a socket");
exit();
}
printf("Success to establish a socket...\n"); /*init sockaddr_in*/
serverSockaddr.sin_family=AF_INET;
serverSockaddr.sin_port=htons(SERVER_PORT);
serverSockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
bzero(&(serverSockaddr.sin_zero),); setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); /*bind socket*/
if(bind(sockfd,(struct sockaddr *)&serverSockaddr,sizeof(struct sockaddr))==-)
{
perror("fail to bind");
exit();
}
printf("Success to bind the socket...\n"); /*listen on the socket*/
if(listen(sockfd,BACKLOG)==-)
{
perror("fail to listen");
exit();
} /*accept a client's request*/ //这里的sinSize还没有处理,具体看下一节
if((clientfd=accept(sockfd,(struct sockaddr *)&clientSockaddr, &sinSize))==-)
{
perror("fail to accept");
exit();
}
printf("Success to accpet a connection request...\n");
printf(" %s join in!\n",inet_ntoa(clientSockaddr.sin_addr)); if((pid=fork())<)
{
perror("fork error\n");
}
else if(pid>)/*child*/
{
/*send datas to client*/
while()
{
fgets(sendBuf,MAX_DATA_SIZE,stdin);
if((sendSize=send(clientfd,sendBuf,strlen(sendBuf),))!=strlen(sendBuf))
{
perror("fail to send datas");
exit();
}
printf("Success to send datas\n");
memset(sendBuf,,MAX_DATA_SIZE);
}
}
else
{
while()
{
/*receive datas from client*/
if((recvSize=recv(clientfd,recvBuf,MAX_DATA_SIZE,))==-)
{
perror("fail to receive datas");
exit();
}
printf("Client:%s\n",recvBuf);
memset(recvBuf,,MAX_DATA_SIZE);
} } return ;
}
本文地址: http://www.cnblogs.com/wunaozai/p/3870194.html
Socket网络编程--聊天程序(2)的更多相关文章
- Socket网络编程--聊天程序(9)
这一节应该是聊天程序的最后一节了,现在回顾我们的聊天程序,看起来还有很多功能没有实现,但是不管怎么说,都还是不错的.这一节我们将讲多服务器问题(高大上的说法就是负载问题了.)至于聊天程序的文件发送(也 ...
- Socket网络编程--聊天程序(1)
很早的一段时间,看了APUE和UNPv1了解了网络编程,但是但是只是看而已,没有具体的实践,趁现在没有什么事做,就来实践了解一下网络编程.写博客保存下来,方便以后用到的时候可以查到. 此次的聊天程序是 ...
- Socket网络编程--聊天程序(8)
上一节已经完成了对用户的身份验证了,既然有了验证,那么接下来就能对不同的客户端进行区分了,所以这一节讲实现私聊功能.就是通过服务器对客户端的数据进行转发到特定的用户上, 实现私聊功能的聊天程序 实现的 ...
- Socket网络编程--聊天程序(6)
这一小节将增加一个用户的结构体,用于保存用户的用户名和密码,然后发给服务器,然后在服务器进行判断验证.这里就有一个问题,以前讲的就是发送字符串是使用char类型进行传输,然后在服务器进行用同样是字符串 ...
- Socket网络编程--聊天程序(7)
接上一小节,本来是计划这一节用来讲数据库的增删改查,但是在实现的过程中,出现了一点小问题,也不是技术的问题,就是在字符界面上比较不好操作.比如要注册一个帐号,就需要弄个字符界面提示,然后输入数字表示选 ...
- Socket网络编程--聊天程序(3)
上一小节,已经讲到可以每个人多说话,而且还没有限制,简单的来说,我们已经完成了聊天的功能了,那么接下来我们要实现什么功能呢?一个聊天程序至少应该支持一对多的通讯吧,接下来就实现多个客户端往服务器发送数 ...
- Socket网络编程--聊天程序(4)
上一小节讲到可以实现多客户端与服务器进行通讯,对于每一个客户端的连接请求,服务器都要分配一个进程进行处理.对于多用户连接时,服务器会受不了的,而且还很消耗资源.据说有个select函数可以用,好像还很 ...
- Socket网络编程--聊天程序(5)
上一小节我们讲了使用select来避免使用多进程的资源浪费问题.上次只是实现了从多个客户端发送数据给服务器端,接下来就要实现从服务器端发送数据给各个客户端. 使用select多路转换处理聊天程序2 c ...
- Socket网络编程--小小网盘程序(5)
各位好呀!这一小节应该就是这个小小网盘程序的最后一小节了,这一节将实现最后的三个功能,即列出用户在服务器中的文件列表,还有删除用户在服务器中的文件,最后的可以共享文件给好友. 列出用户在服务器中的文件 ...
随机推荐
- 048 hive运行的相关配置
一:执行SQL的方式 1.配置的键值 2.minimal下运行fetch 3.设定hive.fetch.task.conversion=more 4.在more下运行fetch 二:虚拟列 一共三个虚 ...
- hdu 1106 去5排序
题目链接:https://vjudge.net/problem/HDU-1106 题目大意: 输入一行数字,如果我们把这行数字中的‘5’都看成空格,那么就得到一行用空格分割的若干非负整数(可能有些整数 ...
- 解决Ubuntu无法进行SSH连接的问题(以及如何使用SSH)
我们在VM中安装好Ubuntu 虚拟机后,经常需要使用Xshell.ssh等工具进行远程连接,方便我们在两个操作系统中进行文件的复制与移动,但是有时候会出现无法连接的问题,原因可能是Ubuntu中默认 ...
- mysql-ubuntu卸载安装mysql
安装MySQL sudo apt-get install mysql-server mysql-client 查看状态 是否是运行中 sudo service mysql status 启动MySQL ...
- Thread中的一些方法
Thread中的一些方法: currentThread() 返回对当前正在执行的线程对象的引用(实现接口方式时使用). sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠( ...
- 基于zepto的移动端轻量级日期插件
前言 做过移动Web开发的同学都知道,移动端日期选择是很常见的需求.在PC端,我们有很丰富的选择,比较出名的就有Mobiscroll和jQuery UI Datepicker.个人看来,这些插件存在的 ...
- Linux启动详解
<概述> Linux启动大致分为一下几个步骤,详细的启动步骤在<启动分析>中详解. 1:首先bios加电自检,初始化(这个过程会检测相关硬件(cpu,内存,显卡,硬盘等)) 2 ...
- android sdk 汉化
作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E-mail: 313134555 @qq.com === ===== ==== ==== == ...
- 洛谷.2709.小B的询问(莫队)
题目链接 /* 数列的最大值保证<=50000(k),可以直接用莫队.否则要离散化 */ #include<cmath> #include<cstdio> #includ ...
- ECS——安装nginx
安装nginx和配置nginx.conf文件 进入home目录,执行以下命令: wget https://nginx.org/download/nginx-1.14.0.tar.gz 下载完成后,执行 ...