多线程编程以及socket编程_Linux程序设计4chapter15
看了Linux程序设计4中文版,学习了多线程编程和socket编程。本文的程序参考自Linux程序设计4的第15章。
设计了一个客户端程序,一个服务端程序。使用TCP协议进行数据传输。
客户端进程创建了一个客户端使用的socket,一个socket地址结构体。设置这个socket地址结构体的端口和地址为要连接的服务端的端口和ip。然后使用客户端的socket尝试连接服务端(connect),如果连接失败直接退出。如果连接成功,则使用这个连接成功的socket进行数据传输(send和recv)。首先向服务端发送一个字节字符型数据,然后接收服务端102个字节字符型数据,不断循环。如果发送和接受出错被捕获到的话(res=-1),关闭socket,退出进程。
服务端程序使用了一个sever_socket,并把这个socket与本机的ip和监听的端口进行绑定,并监听这个socket,accept远端来的连接。Accept成功一次就会获得一个client_socket。这时创建一个新线程,并把这个这个client_socket作为线程参数传给新线程。一个新线程服务一个远端连接,处理他们的数据传输请求(不断的收发数据,循环)。
gcc client2.c -o client2 -lpthread
gcc server2.c -o server2 -lpthread
这个客户和服务端程序有一个很奇特的现象,就是服务端启动之后,接收客户端的连接,每个连接创建一个新线程进行服务。当有多个客户端程序连接服务端(打开多个终端窗口开程序),所有的客户端都在疯狂与服务端进行数据传输时,把其中一个客户端程序(Ctrl+C)掉,这时服务端的进程也会立刻终止,而服务端的终止会连带把其他正在传输数据的客户端进程一起终止掉。对应的出错的客户端和服务端的代码为如下所示。(PS:结束掉客户端不是每次都让服务端挂掉,有时候会使得服务端recv出错返回-1,被捕获,然后安全退出线程,进程依然安全。)
针对这个现象我做了一些测试。1、把客户端改为只收,服务端改为只发。
(客户端崩掉会导致服务端的send的res=-1,100%被捕获到,从而安全退出线程,不会威胁整个进程。
服务端崩掉会导致客户端recv出错为0,但没有被捕获,使得客户端在收不到数据的情况下一直死循环。客户端没有阻塞,recv的返回值是0。)
2、把客户端改为只发,服务端只收。
(客户端崩掉会导致服务端recv出错为0,但没有被捕获,从而多个线程无法退出,在死循环。
服务端崩掉会导致客户端send出错为-1,被捕获,从而安全退出。)
所以上面的奇特现象出现的原因是:
在对端崩溃之后,send出错只会返回-1,而recv出错有时返回-1,大多数时候返回0。只有在recv出错为0没有被捕获,而又继续send,才会导致进程立刻死亡(此时无法捕获send的错误)。
解决办法是:
两端的程序增加捕获recv的出错为0的情况,具体代码是if((res==-1)||(res==0))。这样无论哪端崩掉,对端都能够捕获出错的情况,处理出错的情况,不会出现进程突然死亡现象。
Client2.C程序:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{ //测试方法,把client2和server2放在相同
int sockfd; //或者不同文件夹下都可以
int len,i,res; //一个终端运行./client2 另外一个终端
struct sockaddr_in address; //运行 ./server2 就可以看到结果了
int result;
char ch = 'A'; //奇怪,一个client运行多个版本,每次获取的
char buff[1024]; //居然是同一个socket。改个名字也不行
sockfd = socket(AF_INET,SOCK_STREAM,0); //
printf("socket is %d\n",sockfd);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.131.129");
address.sin_port = htons(9734);
len = sizeof(address);
result = connect(sockfd,(struct sockaddr*)&address,len);
if(result == -1)
{
perror("oops:client1");
exit(-1);
}
memset(buff,0,1024);
i = 0;
//for(i=0;i<100;i++)
for(;;)
{
res = send(sockfd,&ch,1,0);
if(res==-1)
{
printf("send error,res is %d,exiting program\n",res);
close(sockfd);
return(-1);
}
i++;
memset(buff,0,102);
res = recv(sockfd,buff,102,0);
if(res==-1) //if((res==-1)||(res==0))
{
printf("recv error,res is %d,exiting program\n",res);
close(sockfd);
return(-1);
}
printf("socket:%d,buff is %s,i is %d\n",sockfd,buff,i);
/**/
}
printf("exiting program\n");
close(sockfd);
return 0;
}
Server2.C程序:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void* thread1(void* arg)
{
int client_sock;
char buff[1024];
char ch;
int i,res;
memset(buff,0,1024);
strncpy(buff,"this is server",14);
client_sock = (int)arg;
printf("para from main thread,socket = %d\n",client_sock);
printf("before sending,buff is:%s\n",buff);
//for(i=0;i<100;i++)
for(;;)
{
//res = read(client_sock,&ch,1);
//if(res==-1)
//{
// printf("read error\n");
// close(client_sock);
// break;
// //pthread_exit((void*)(-1));
//}
res = recv(client_sock,&ch,1,0);
if(res==-1)
//if((res==-1)||(res==0))
{
printf("recv error!res is %d\n",res);
close(client_sock);
break;
//pthread_exit((void*)(-1));
}
res = send(client_sock,buff,102,0);
if(res==-1)
{
printf("send error,res is %d\n",res);
close(client_sock);
break;
//pthread_exit((void*)(-1));
}
/**/
}
printf("exiting thread\n");
close(client_sock);
return ((void*)0);
}
int main(int argc,char* argv[])
{
int result,re;
pthread_t a_thread;
int server_sockfd,client_sockfd;
int server_len,client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket(AF_INET,SOCK_STREAM,0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("192.168.131.129");
server_address.sin_port = htons(9734); //注意这里的sin_port是两个字节的
server_len = sizeof(server_address);
result = bind(server_sockfd,(struct sockaddr*)&server_address,server_len);
if(result!=0)
{
printf("bind failed\n");
exit(1);
}
result = listen(server_sockfd,5);
if(result!=0)
{
printf("listen failed\n");
exit(1);
}
while(1)
{
char ch;
printf("server waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address,&client_len);
printf("accept one client,socket:%d\n",client_sockfd);
re = pthread_create(&a_thread,NULL,thread1,(void*)client_sockfd);
if(re!=0)
{
printf("create thread failed\n");
exit(EXIT_FAILURE);
}
//read(client_sockfd,&ch,1);
//ch++;
//write(client_sockfd,&ch,1);
//close(client_sockfd);
}
return 0;
}
多线程编程以及socket编程_Linux程序设计4chapter15的更多相关文章
- 第九章:Python高级编程-Python socket编程
第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...
- Linux高级编程--10.Socket编程
Linux下的Socket编程大体上包括Tcp Socket.Udp Socket即Raw Socket这三种,其中TCP和UDP方式的Socket编程用于编写应用层的socket程序,是我们用得比较 ...
- Python学习笔记——基础篇【第七周】———FTP作业(面向对象编程进阶 & Socket编程基础)
FTP作业 本节内容: 面向对象高级语法部分 Socket开发基础 作业:开发一个支持多用户在线的FTP程序 面向对象高级语法部分 参考:http://www.cnblogs.com/wupeiqi/ ...
- iOS网络编程笔记——Socket编程
一.什么是Socket通信: Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换.这个双向连路的一端称为socket.socket通常用来实现客户方和服务方的连接.socket是T ...
- C#网络编程:Socket编程
套接字简介:套接字最早是Unix的,window是借鉴过来的.TCP/IP协议族提供三种套接字:流式.数据报式.原始套接字.其中原始套接字允许对底层协议直接访问,一般用于检验新协议或者新设备问题,很少 ...
- 【Linux编程】socket编程
套接字是通信端点的抽象.文件描写叙述符用open函数创建,而套接字描写叙述符用socket函数创建.socket函数原型例如以下: int socket(int domain, int type, i ...
- 【IOS网络编程】socket编程 - Asyncsocket
Phone的标准推荐是CFNetwork 库编程,其封装好的开源库是 cocoa AsyncSocket库,用它来简化CFNetwork的调用,它提供了异步操作 主要特性有: 队列的非阻塞的读和写,而 ...
- Linux C Socket 编程
1 Socket 是什么 Socket(套接字),就是对 网络上进程通信 的 端点 的 抽象.一个 Socket 就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制. 从所处的位置来 ...
- 【Socket编程】Java通信是这样炼成的
简介 网络无处不在,移动互联时代也早已到来,单机版程序慢慢的已没有生命力,所有的程序都要能够访问网络,比如 QQ 网络聊天程序.迅雷下载程序等,这些程序都要同网络打交道,本次将与各位小伙伴们分享的就是 ...
随机推荐
- linux内核编译与开发
一.Linux内核简介linux kernel map: linux 系统体系结构: linux kernel体系结构: arm有7种工作模式,x86也实现了4个不同级别RING0-RING3,RIN ...
- 一点一点学写Makefile-1
相信很多Linux开发者 都得自己来写Makefile,刚开始学习学写这个的时候都会碰到很多困难,我之前没有自己独立完成过Makefile,都是在公司已有的模板上添加.现在突然有一个很大的想法就是从零 ...
- 关于git的使用
一.关于GIT Git --- The stupid content tracker, 傻瓜内容跟踪器.Linus Torvalds 是这样给我们介绍 Git 的. Git 是用于 Linux内核 ...
- Jerry的WebClient UI 42篇原创文章合集
我要感谢CRM On Premise, 因为在这个产品上做开发让我得以使用WebClient UI框架.有些朋友觉得这个SAP自己发明的基于HTML+ABAP的MVC框架,和现在流行的三驾马车(Ang ...
- Jmeter启动报错:unable to access jarfile ApacheJmeter.jar error 原因:下载的src包没有这个jar包,需下载binary包
安装好jdk并配置了环境变量,下载Jmeter包解压启动jemter.bat提示 unable to access jarfile ApacheJmeter.jar error 原因: 从官网 htt ...
- POSIX多线程—线程基本概念
http://blog.csdn.net/livelylittlefish/article/details/7957007 作者:阿波链接:http://blog.csdn.net/livelylit ...
- 十天精通CSS3
课程地址:http://www.imooc.com/learn/33 第1章 初识CSS3 CSS3课程列出第一站,先带领大家进入CSS3的世界,探索CSS3的魅力! 你做好准备了吗? 第2章 边框 ...
- ACM-ICPC (10/12)
01分数规划 背景:根据楼教主回忆,曾经在一场比赛中秒掉了一道最优比例生成树问题,导致很多人跟风失败,最终悲剧. 什么是01分数规划呢? 这样的等式求最大,最小即为01分数规划. 如果你不知道该如何 ...
- 4519: [Cqoi2016]不同的最小割
4519: [Cqoi2016]不同的最小割 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 489 Solved: 301 [Submit][Stat ...
- [USACO17JAN]Subsequence Reversal
嘟嘟嘟 这题刚开始是什么思路也没有,关键是不知道怎么解决序列反转的问题. 然后我就想到如果暴力反转一个序列的话,实际上就是不断交换数组中的两个数ai和aj,同时要满足交换的数不能交叉. 然后又看了一眼 ...