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编程(四)
经过两周的等待,终于可以回归我正常的学习之旅了,表哥来北京了在我这暂住,晚上回家了基本在和他聊天,周末带他在北京城到处乱转,几乎剥夺了我自由学习的时间了,不过,亲人之情还是很难得的,工作学习并不是生活 ...
随机推荐
- iOS支付宝集成详细流程
实现支付宝支付的准备工作: 1.向支付宝签约,成为支付宝的商户 签约完成后,支付宝会提供一些必要的数据给我们 商户ID:partner 账号ID:seller 即支付宝账号 签约需要营业执照 2.获取 ...
- Swift学习--常量.变量.数据类型的使用(二)
一.Swift中的数组 //Swift中的数组 //NSArray *arr = @["",""]; //和OC数组的区别就是去掉前面的@ let arr11 ...
- 获取byte数组的实际使用长度
背景:byte.length只能获取到初始化的byte数组长度,而不是实际使用的长度,因此想要获取到实际的使用长度只能靠其他方法实现. 方法一: public class ByteActualLeng ...
- kettle初探
Kettle是Pentaho的一个组件,主要用于数据库间的数据迁移,到我用过的4.2版,还不支持noSQL,不知道4.4是不是支持了. Kettle自己有三个主要组件:Spoon,Kitchen,Pa ...
- jsp中的四种对象作用域
page:当前页面,也就是只要挑到别的页面就失效了,可以近似理解为java的this对象 request:一次会话,简单的理解就是一次请求范围内有效,例如如果通过forward方式跳转,则forwar ...
- Gulp使用入门操作十一步压缩JS
前提需要安装nodejs 一. 全局安装Gulp npm install -g gulp 二.新建一个 gulpfile.js 文件 chapter2└── gulpfile.js 三.在 gulpf ...
- VS2010 调试窗口一闪而过解决方法
若此时进行的操作是编译(F5),可先运行程序(Ctrl+F5),若仍然一闪而过,用下面方法解决. 方法一: 1.要有头文件cstdlib,在程序最后写一句(return之前)添加:system(&qu ...
- POJ 2777 Count Color(线段树之成段更新)
Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 33311 Accepted: 10058 Descrip ...
- JavaScript的几种函数的结构形式
匿名函数,普通函数,变量函数,基于对象的方法 介绍它们的优劣点(性能,执行条件,可维护性,适合大型还是小型) Javascript有着灵活多变的函数方法,具体选用何种形式,都会极大地影响应用程序的编写 ...
- NOIP2010提高组 关押罪犯 -SilverN
(洛谷P1525) 题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”( ...