//网络编程--客户端
#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多线程升级版)的更多相关文章

  1. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  2. Linux网络编程(四)

    在linux网络编程[1-3]中,我们编写的网络程序仅仅是为了了解网络编程的基本步骤,实际应用当中的网络程序并不会用那样的.首先,如果服务器需要处理高并发访问,通常不会使用linux网络编程(三)中那 ...

  3. Linux网络编程3——socket

    宏定义 首先介绍两个宏定义,看如下代码 代码1 /************************************************************************* & ...

  4. Linux网络编程:socket文件传输范例

    基于TCP流协议的socket网络文件传输Demo: 实现:C语言功能:文件传输(可以传任何格式的文件) /********************************************** ...

  5. Linux网络编程四、UDP,广播和组播

    一.UDP UDP:是一个支持无连接的传输协议,全称是用户数据包协议(User Datagram Protocol).UDP协议无需像TCP一样要建立连接后才能发送封装的IP数据报,也是因此UDP相较 ...

  6. linux网络编程(socket)之面向连接(TCP/IP)

    1.流程 服务器: 创建socket: 绑定端口: 监听: 监听到有连接请求,接受请求: 建立连接,开始对话. 客户端: 创建socket: 请求建立连接: 连接建立成功,开始对话. 2.实例代码 / ...

  7. Linux网络编程socket选项之SO_LINGER,SO_REUSEADDR

    from http://blog.csdn.net/feiyinzilgd/article/details/5894300 Linux网络编程中,socket的选项很多.其中几个比较重要的选项有:SO ...

  8. Linux网络编程:UDP Socket编程范例

    TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯 ...

  9. linux网络编程之socket编程(四)

    经过两周的等待,终于可以回归我正常的学习之旅了,表哥来北京了在我这暂住,晚上回家了基本在和他聊天,周末带他在北京城到处乱转,几乎剥夺了我自由学习的时间了,不过,亲人之情还是很难得的,工作学习并不是生活 ...

随机推荐

  1. java多线程系列1--线程实现与调度

    java的重要功能之一就是内部支持多线程,这一系列文章将详细剖析java多线程的基础知识 多线程概述 多线程引入 程序只有一个执行流程,所以这样的程序就是单线程程序. 假如一个程序有多条执行流程,那么 ...

  2. android 学习运用海马模拟器教程与android环境的搭建

    第三方海马玩模拟器 第一天的学习android采用的模拟器是海马,因此就分享给大家海马模拟器的相关步骤: 海马玩模拟器官网: http://droid4x.haimawan.com 下载相关平台的模拟 ...

  3. 协议(Protocol)---实例

    协议:声明一些必须实现的方法和选择实现的方法,用来声明一些方法,即一个Protocol是由一系列的方法声明组成的. 建立协议文件步骤:将鼠标放到文件列表处,利用快捷键 command +N 健,得到如 ...

  4. Objective-C之优雅的命名

    There are only two hard things in Computer Science: cache invalidation and naming things.在计算机科学中只有两件 ...

  5. iOS 编译报错

    Undefined symbols for architecture i386: “_OBJC_CLASS_$_XXX”, referenced from: objc-class-ref in XXX ...

  6. spring boot 1.4.1 with jsp file sample

    <!--pom.xml--> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=" ...

  7. Xcode的内存清理

    1.删除Xcode中多余的证书provisioning profile 手动删除: 打开finder,然后在最上面的前往中前往下方的路径,就可以看到你xcode运行到现在使用过的证书provision ...

  8. 每日Scrum--No.4

    Yesterday:学习迪杰斯特拉算法并进行简单的编写代码 Today:继续编写代码 Problem:变量名的定义出错,造成调用的时候出错,不过改过来就好了.算法的编写不全面,漏掉个别语句,如在调试的 ...

  9. c# 其他技术学习

    1.注册表编辑 为了方便对注册表进行操作,.NET提供了Registry类和RegistryKey类 2.API函数的应用 (1)自定义特性的代码:在类.属性.方法的上方加上“[]”的代码 (2)有个 ...

  10. 物理系统迁移虚拟化P2V技术

    企业搭建虚拟化平台之后的第一件事肯定是将现有的服务器应用业务转移到虚拟服务器上,这就是虚拟化整合服务器的第一步,也是虚拟化程序的基础功能之一:P2V的转化功能. AD:   企业搭建虚拟化平台之后的第 ...