多线程编程以及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;

}

原文地址:https://www.cnblogs.com/znwang/p/9235692.html

时间: 2024-08-03 07:56:27

多线程编程以及socket编程_Linux程序设计4chapter15的相关文章

02-【IOS网络编程】socket编程 - Asyncsocket

socket编程Asyncsocket iPhone的标准推荐是CFNetwork 库编程,其封装好的开源库是 cocoa AsyncSocket库,用它来简化CFNetwork的调用,它提供了异步操作 主要特性有: 队列的非阻塞的读和写,而且可选超时.你可以调用它读取和写入,它会当完成后告知你 自动的socket接收.如果你调用它接收连接,它将为每个连接启动新的实例,当然,也可以立即关闭这些连接 委托(delegate)支持.错误.连接.接收.完整的读取.完整的写入.进度以及断开连接,都可以通

1.socket编程:socket编程,网络字节序,函数介绍,IP地址转换函数,sockaddr数据结构,网络套接字函数,socket相关函数,TCP server和client

 1  Socket编程 socket这个词可以表示很多概念: 在TCP/IP协议中,"IP地址+TCP或UDP端口号"唯一标识网络通讯中的一个进程,"IP 地址+端口号"就称为socket. 在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接.socket本身有"插座"的意思,因此用来描述网络连 接的一对一关系. TCP/IP协议最早在BSD UNIX上实现,

iOS网络编程笔记——Socket编程

一.什么是Socket通信: Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换.这个双向连路的一端称为socket.socket通常用来实现客户方和服务方的连接.socket是TCP/IP协议的一个十分流行的编程接口.一个socket由一个IP地址和一个端口号唯一确定.TCP/IP协议的传输层又有两种协议:TCP(传输控制协议)和UDP(用户数据报协议).TCP是基于连接的,而UDP是无连接的:TCP对系统资源的要求较多,而UDP少:TCP保证数据的正确性而UDP可能丢包:

Python学习笔记——基础篇【第七周】———FTP作业(面向对象编程进阶 &amp; Socket编程基础)

FTP作业 本节内容: 面向对象高级语法部分 Socket开发基础 作业:开发一个支持多用户在线的FTP程序 面向对象高级语法部分 参考:http://www.cnblogs.com/wupeiqi/p/4766801.html metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好 Socket 编程 参考:http://www.cnblogs.co

【Linux编程】socket编程

套接字是通信端点的抽象.文件描写叙述符用open函数创建,而套接字描写叙述符用socket函数创建.socket函数原型例如以下: int socket(int domain, int type, int protocol); // 返回值:成功返回套接字描写叙述符,失败返回-1 domain域确定通信特性.不同的域表示地址的格式不同,表示域的常数以AF开头.表示地址族(address family): watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb

Linux高级编程--10.Socket编程

Linux下的Socket编程大体上包括Tcp Socket.Udp Socket即Raw Socket这三种,其中TCP和UDP方式的Socket编程用于编写应用层的socket程序,是我们用得比较多的,而Raw Socket则用得相对较少,不在本文介绍范围之列. TCP Socket 基于TCP协议的客户端/服务器程序的一般流程一般如下: 它基本上可以分为三个部分: 一.建立连接: 服务器调用socket().bind().listen()完成初始化后,调用accept()阻塞等待,处于监听

tcp编程、socket编程

tcp编程(需要建立连接,三次握手,四次挥手,然后发送信息流,数据包是有序的) udp编程(知道IP.端口直接发送数据,数据包可能是无序的) 1.客户端和服务器客 socket编程 1.服务端的处理流程 a.监听端口 b.接收客户端的链接 c.创建goroutine,处理该链接 2.客户端的处理流程 a.建立与服务端的链接 b.进行数据收发 c.关闭链接 3.服务端代码 package main import ( "fmt" "net"//导入socket的包 )

六、网络编程(socket编程)

一.客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网处处是C/S架构 比如百度网站是服务端,浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端提供微信服务,需要下载微信安装包安装使用才可以去聊微信. C/S架构与socket的关系: 用socket就是为了完成C/S架构的开发 server端(必须遵守的): 1.位置必须固定死,绑定一个固定的地址 2.对外一直提供服务,稳定运行 3.支持并发(让多个客户端感觉是同时被服务着) 二.OSI七层 1.引子 须

【网络编程】socket编程

socket概念 socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递. 我们知道网络 通信 都 是基于 ip+port 方能定位到目标的具体机器上的具体服务,操作系统有0-65535个端口,每个端口都可以独立对外提供服务,如果 把一个公司比做一台电脑 ,那公司的总机号码就相当于ip地址, 每个员工的分机号就相当于端口, 你想找公司某个人,必须 先打电话到总机,然后再转分机 . 建立一个socket必须至少有2端, 一个服务端,一个客户端, 服务