Linux 网络编程四(socket多线程升级版)
//网络编程--客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h> #include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h> /*
强调:当客户端连接服务器时,服务器会产生一个新的文件描述符(套接字)与客户端交互,这个新的套接字不是服务器端的监听套接字
套接字是全双工的,在一个网络管道中的两端,每端都可以进行读写操作。
*/ typedef struct _recvmodel
{
int st;
struct sockaddr_in * addr;
} RecvModel; //send message
void * send_thread(void *arg)
{
if (arg == NULL)
{
printf("param is not allow NULL!\n");
return NULL;
}
int st = *(int *) arg;
char buf[] = { };
while ()
{
read(STDIN_FILENO, buf, sizeof(buf));
if (send(st, buf, strlen(buf), ) == -)
{
printf("send failed ! error message %s\n", strerror(errno));
return NULL;
}
memset(buf, , sizeof(buf));
}
return NULL;
} //recv message
void * recv_thread(void * arg)
{
if (arg == NULL)
{
printf("param is not allow NULL!\n");
return NULL;
}
RecvModel * model = (RecvModel *) arg;
int flag = ;
char buf[] = { };
while ()
{
flag = recv(model->st, buf, sizeof(buf), );
if (flag == )
{
printf("对方已经关闭连接!\n");
return NULL;
} else if (flag == -)
{
printf("recv failed ! error message : %s\n", strerror(errno));
return NULL;
}
printf("from %s:%s", inet_ntoa(model->addr->sin_addr), buf);
memset(buf, , sizeof(buf));
}
return NULL;
} int main(int arg, char *args[])
{
//打开socket
int st = socket(AF_INET, SOCK_STREAM, );
if (st == -)
{
printf("open socket failed! error message:%s\n", strerror(errno));
return -;
}
//定义IP地址结构
struct sockaddr_in addr;
memset(&addr, , sizeof(addr));
//设置TCP/IP连接
addr.sin_family=AF_INET;
//设置端口号
addr.sin_port = htons();
//设置允许连接地址
addr.sin_addr.s_addr = inet_addr("192.168.1.102");
//connect server
int numx = connect(st, (struct sockaddr *) &addr, sizeof(addr));
if (numx == -)
{
printf("connect server failed ! error message :%s\n", strerror(errno));
goto END;
} RecvModel model;
model.st = st;
model.addr = &addr;
//开启多线程--线程1接收消息,线程2发送消息
pthread_t thr1, thr2;
if (pthread_create(&thr1, NULL, send_thread, &st) != )
{
printf("create thread failed ! \n");
goto END;
}
if (pthread_create(&thr2, NULL, recv_thread, &model) != )
{
printf("create thread failed ! \n");
goto END;
}
pthread_join(thr1, NULL);
pthread_join(thr2, NULL);
END: close(st);
return ;
}
//网络编程--服务端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h> #include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h> typedef struct _recvmodel
{
int st;
struct sockaddr_in * addr;
} RecvModel; //send message
void * send_thread(void *arg)
{
if (arg == NULL)
{
printf("param is not allow NULL!\n");
return NULL;
}
int st = *(int *) arg;
char buf[] = { };
while ()
{
read(STDIN_FILENO, buf, sizeof(buf));
if (send(st, buf, strlen(buf), ) == -)
{
printf("send failed ! error message %s\n", strerror(errno));
return NULL;
}
memset(buf, , sizeof(buf));
}
return NULL;
} //recv message
void * recv_thread(void * arg)
{
if (arg == NULL)
{
printf("param is not allow NULL!\n");
return NULL;
}
RecvModel * model = (RecvModel *) arg;
int flag = ;
char buf[] = { };
while ()
{
flag = recv(model->st, buf, sizeof(buf), );
if (flag == )
{
printf("对方已经关闭连接!\n");
return NULL;
} else if (flag == -)
{
printf("recv failed ! error message : %s\n", strerror(errno));
return NULL;
}
printf("from %s:%s", inet_ntoa(model->addr->sin_addr), buf);
memset(buf, , sizeof(buf));
}
return NULL;
} int main(int arg, char *args[])
{ //short port = atoi(args[1]);
//打开socket
int st = socket(AF_INET, SOCK_STREAM, );
if (st == -)
{
printf("open socket failed! error message:%s\n", strerror(errno));
return -;
}
//设置系统地址可重用
int on = ;
if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -)
{
printf("setsockpot failed ! error message %s\n", strerror(errno));
goto END;
}
//定义IP地址结构
struct sockaddr_in addr;
memset(&addr, , sizeof(addr));
//设置TCP/IP连接
addr.sin_family = AF_INET;
//设置端口号
addr.sin_port = htons();
//设置允许连接地址
addr.sin_addr.s_addr = htonl(INADDR_ANY);
//bind ip
if (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -)
{
printf("bind ip failed ! error message :%s\n", strerror(errno));
goto END;
}
//监听连接
if (listen(st, ) == -)
{
printf("listen failed ! error message :%s\n", strerror(errno));
goto END;
}
//接收客户端连接(阻塞)
struct sockaddr_in client_addr;
memset(&client_addr, , sizeof(client_addr));
socklen_t client_addrlen = sizeof(client_addr);
//强调:这里的client_addrlen并不是为了在函数中设置client_addrlen的值,而是通过client_addrlen的值来判断client_addr是一个什么类型的结构,
//所以这里client_addrlen设置为0是错误的,必须是struct sockaddr_in这个结构的大小,不然返回值不正确
int client_st = accept(st, (struct sockaddr *) &client_addr,
&client_addrlen);
if (client_st == -)
{
printf("accept failed ! error message :%s\n", strerror(errno));
goto END;
}
RecvModel model;
model.st = client_st;
model.addr = &client_addr;
printf("accept by=%s\n",inet_ntoa(client_addr.sin_addr));
//开启多线程--线程1接收消息,线程2发送消息
pthread_t thr1, thr2;
if (pthread_create(&thr1, NULL, send_thread, &client_st) != )
{
printf("create thread failed ! \n");
goto END;
}
if (pthread_create(&thr2, NULL, recv_thread, &model) != )
{
printf("create thread failed ! \n");
goto END;
}
pthread_join(thr1, NULL);
pthread_join(thr2, NULL);
//关闭客户端管道
close(client_st);
END: close(st);
return ;
}
.SUFFIXES:.c .o
CC=gcc
SRCS1=mserver.c
SRCS2=mclient.c
OBJS1=$(SRCS1:.c=.o)
OBJS2=$(SRCS2:.c=.o)
EXEC1=mserv
EXEC2=mcli start:$(OBJS1) $(OBJS2)
$(CC) -o $(EXEC1) $(OBJS1) -lpthread
$(CC) -o $(EXEC2) $(OBJS2) -lpthread
@echo "^_^ ------ OK ------ ^_^"
.c.o:
$(CC) -Wall -g -o $@ -c $<
clean:
rm -f $(OBJS1)
rm -f $(OBJS2)
rm -f $(EXEC1)
rm -f $(EXEC2)
小结:这段升级版程序花费3小时,出现一个错误提示:" Transport endpoint is not connected",我仔细查找资料,
网上说是socket套接字不对,可我程序中套接字是正确的,
我没有办法,但是我有一个成功的程序,就是第一版socket程序,我将原来的socket程序复制到我的新程序中,一句句替换,终于发现这个问题
问题:我缺少addr.sin_family = AF_INET;//将网络地址类型设置为TCP/IP协议;这句代码。缺少这段代码是导致报错的主要原因。
另外注意我代码中强调的内容--网络管道是全双工的
Linux 网络编程四(socket多线程升级版)的更多相关文章
- linux网络编程-(socket套接字编程UDP传输)
今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...
- Linux网络编程(四)
在linux网络编程[1-3]中,我们编写的网络程序仅仅是为了了解网络编程的基本步骤,实际应用当中的网络程序并不会用那样的.首先,如果服务器需要处理高并发访问,通常不会使用linux网络编程(三)中那 ...
- Linux网络编程3——socket
宏定义 首先介绍两个宏定义,看如下代码 代码1 /************************************************************************* & ...
- Linux网络编程:socket文件传输范例
基于TCP流协议的socket网络文件传输Demo: 实现:C语言功能:文件传输(可以传任何格式的文件) /********************************************** ...
- Linux网络编程四、UDP,广播和组播
一.UDP UDP:是一个支持无连接的传输协议,全称是用户数据包协议(User Datagram Protocol).UDP协议无需像TCP一样要建立连接后才能发送封装的IP数据报,也是因此UDP相较 ...
- linux网络编程(socket)之面向连接(TCP/IP)
1.流程 服务器: 创建socket: 绑定端口: 监听: 监听到有连接请求,接受请求: 建立连接,开始对话. 客户端: 创建socket: 请求建立连接: 连接建立成功,开始对话. 2.实例代码 / ...
- Linux网络编程socket选项之SO_LINGER,SO_REUSEADDR
from http://blog.csdn.net/feiyinzilgd/article/details/5894300 Linux网络编程中,socket的选项很多.其中几个比较重要的选项有:SO ...
- Linux网络编程:UDP Socket编程范例
TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯 ...
- linux网络编程之socket编程(四)
经过两周的等待,终于可以回归我正常的学习之旅了,表哥来北京了在我这暂住,晚上回家了基本在和他聊天,周末带他在北京城到处乱转,几乎剥夺了我自由学习的时间了,不过,亲人之情还是很难得的,工作学习并不是生活 ...
随机推荐
- Objective-C中@encode的使用
今天看Mansonry的代码时,碰到一个生僻的关键字(也许只是自己没用过).:-) @encode => 将给定类型编码为内部表示的字符串. 为了方便自己查阅,顺便也写个小例子,贴在这里,实践 ...
- XCode的安装包校验伪真
校验文件方法:shasum xxx.dmgORmd5 xxx.dmg - Xcode_7.1.dmgMD5:8962e1a843a51232b92a908b6cfb180dSHA-1:d4e9b9e8 ...
- windows 7 下,如何统计某文件夹下 视频总时长
由于项目需要,我需要给系统加权限,这真是一个让人头疼的问题,如果要每个业务方法都加上权限判断逻辑,那真的不敢想象是多么大的工作量,日后有变动的话,我会不会发疯? 所以我必须利用之前学到的AOP编程,在 ...
- Android keystore 密码忘记了的找回办法
keystore密码忘记了,准备给自己的应用发布一个新版本,在apk打包时,发现之前的用的keystore密码忘了.如果换一个keystore,则之前已经安装应用的用户就必须手工卸载原应用才能安装,非 ...
- HTTPS(SSL/TLS) 原理之深入浅出
注:本文参考自网络上的多篇HTTPS相关文章,本人根据自己的理解,进行一些修改,综合. 1. 必要的加密解密基础知识 1)对称加密算法:就是加密和解密使用同一个密钥的加密算法.因为加密方和解密方使用的 ...
- cocos2d-x之悦动的小球
发现问题:update()函数不能用virtual前缀 主: bool HelloWorld::init() { if ( !LayerColor::initWithColor(Color4B(255 ...
- POJ 2513 Colored Sticks(欧拉回路,字典树,并查集)
题意:给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的. 无向图存在欧拉路的充要条件为: ① 图是连通的: ② 所有节 ...
- SSAS CUBE TEST CASES
经过周末两天和今天的努力,基本上完成并修复了一些bug并且集成到我的MSBIHelper项目中去,可以进行数据测试了.效果图如下: 可以帮助开发人员快速生成等值的Tsql和mdx查询,辅助测试人员快速 ...
- 探索 OpenStack 之(14):OpenStack 中 RabbitMQ 的使用
本文是 OpenStack 中的 RabbitMQ 使用研究 两部分中的第一部分,将介绍 RabbitMQ 的基本概念,即 RabbitMQ 是什么.第二部分将介绍其在 OpenStack 中的使用. ...
- NOIP2008提高组火柴棒等式(模拟)——yhx
题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: 注意: 加号与等号各自 ...