20.Linux:网络编程(TCP协议-简单版本):client和server(原创)
2016-09-01 10:01
696 查看
需要注意的地方:
1.两端的socket函数通信类型(IPv4还是IPv6),通信协议(TCP还是UDP)都要一致
2.两端对服务器的设置都要一致,对于客户端而言,这些设置信息是用来给connect函数提供连接信息的
3.特别注意:在服务器端发送和接收信息,send和recv函数的套接字必须用客户端的,也就是accept函数的返回值
下面是程序:
客户端:
服务器端:
两个重要函数:
1.accept()函数
int accept(int sockfd,struct
sockaddr *addr,socklen_t *addrlen);
sockfd,
利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连接;
addr<
4000
/span>, 指向struct
sockaddr的指针,该结构用通讯层服务器对等套接字的地址(一般为客户端程序的地址)填写,返回地址addr的确切格式由套接字的地址类别(比如TCP或UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,应该置为NULL;
备注:addr是个指向局部数据结构sockaddr_in的指针,这就是要求接入的套接字(地址和指针)。
addrlen,
一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值,函数返回时包含对等地址(一般为服务器地址)的实际数值;
accept()用来接受参数s 的socket 连线. 参数s 的socket 必需先经bind()、listen()函数处理过,
当有连线进来时accept()会返回一个新的socket 处理代码, 往后的数据传送与读取就是经由新的socket处理, 这个新的socket与原来的socket不一样,原来参数s
的socket 能继续使用accept()来接受新的连线要求. 连线成功时, 参数addr 所指的结构会被系统填入远程主机的地址数据(客户端所传来的服务器端的具体地址), 参数addrlen 为scokaddr 的结构长度.
再次调用accept()可以接受下一个客户端的连接请求,并再次返回一个新的套接字(与socket()返回的套接字、之前accept()返回的套接字都不同的新的套接字)。这个新的套接字用于与这次接受的客户端之间的通信。
2.connect()函数
connect()用来将参数sockfd
的socket 连至参数serv_addr 指定的网络地址. 结构sockaddr请参考bind(). 参数addrlen 为sockaddr 的结构长度.
connect函数完成主动连接的过程,功能是完成一个有连接协议的连接过程,对于TCP来说就是那个三路握手过程.
int connect(int sockfd, const struct sockaddr* server_addr,socklen_t addrlen)
返回:0──成功, -1──失败。
参数sockfd
指定数据发送的套接字,解决从哪里发送的问题。内核需要维护大量IO通道,所以用户必需通过这个参数告诉内核从哪个IO通道,此处就是从哪个socket接口中发送数据。sockfd是先前socket返回的值。
参数server_addr
指定数据发送的目的地,也就是服务器端的地址。这里服务器是针对connect说的,因为connect是主动连接的一方调用的,所以相应的要存在一个被连接的一方,被动连接的一方需要调用listen以接受connect的连接请求,如此被动连接的一方就是服务器了。
参数addrlen
指定server_addr结构体的长度。我们知道系统中存在大量的地址结构,但socket接口只是通过一个统一的结构来指定参数类型,所以需要指定一个长度,以使内核在进行参数复制的时候有个有个界限。
1.两端的socket函数通信类型(IPv4还是IPv6),通信协议(TCP还是UDP)都要一致
2.两端对服务器的设置都要一致,对于客户端而言,这些设置信息是用来给connect函数提供连接信息的
3.特别注意:在服务器端发送和接收信息,send和recv函数的套接字必须用客户端的,也就是accept函数的返回值
下面是程序:
客户端:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define SERVPORT 3336 #define MAXDATASIZE 100 main(int argc,char *argv[]) { int sendbytes,recvbytes; int sockfd,serv_fd; char buf[MAXDATASIZE]; struct sockaddr_in serv_addr;//这里是设置要连接的服务器的信息,用什么类型地址,服务器端口号多少,地址多少 struct hostent *host; if(argc < 2) { fprintf(stderr,"Please enter the server's hostname!\n"); exit(1); } if (( host = gethostbyname(argv[1])) == NULL) { perror("gethostbyname"); exit(1); } //** creat socket if (( sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) { perror("socket"); exit(1); } //设置需要连接的服务器的信息 serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(SERVPORT);//先将主机字节序转换为网络字节序,再赋值 serv_addr.sin_addr = *((struct in_addr *)host->h_addr); bzero(&(serv_addr.sin_zero),8);//置字节字符串serv_addr.sin_zero的前8个字节为零。 if ( connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr)) == -1)//serv_addr强制转换为sockaddr { perror("connect"); exit(1); } //向服务器端发送信息,注意send的套接字为自己本身 if((sendbytes = send(sockfd,"hello",6,0)) == -1) { perror("send"); exit(1); } //接受来自服务器端的信息,注意recv的套接字为自己本身 if(recvbytes = recv(sockfd,buf,sizeof(buf),0) == -1) { perror("recv"); exit(1); } printf("The client receive: %s\n",buf); close(sockfd); }
服务器端:
#include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/un.h> #include <sys/time.h> #include <sys/ioctl.h> #include <unistd.h> #include <netinet/in.h> #define SERVPORT 3336 #define BACKLOG 10 #define MAX_CONNECTED_NO 10 #define MAXDATASIZE 100 int main() { struct sockaddr_in server_sockaddr,client_sockaddr; int sin_size,recvbytes,sendbytes; fd_set readfd; fd_set writefd; int sockfd,client_fd; char buf[MAXDATASIZE]; if (( sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)//此处必须跟客户端保持一致,都用IPv4和TCP { perror("socket"); exit(1); } printf("socket success!sockfd = %d\n",sockfd); //服务器本身端口号设置,客户端必须与此处保持一致才能连接上 server_sockaddr.sin_family = AF_INET; server_sockaddr.sin_port = htons(SERVPORT);//端口号与客户端保持一致 server_sockaddr.sin_addr.s_addr = INADDR_ANY; bzero(&(server_sockaddr.sin_zero),8); if (bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr)) == -1)//第二个参数这里是本地地址(服务器地址)所在的结构体指针 { perror("bind"); exit(1); } printf("bind success!\n"); if (listen(sockfd,BACKLOG) == -1)//设置最大可以监听的数量 { perror("listen"); exit(1); } printf("listening...\n"); if (( client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr,&sin_size)) == -1)//这里的客户端地址会被发送过来连接的地址填好(客户端程序的 //<span style="font-family: Arial, Helvetica, sans-serif;">服务</span><span style="font-family: Arial, Helvetica, sans-serif;">器地址)</span> { perror("accept"); exit(1); } //服务器端的发送和接收套接字必须都是客户端的---即accept函数的返回值 if (( recvbytes = recv(client_fd,buf,MAXDATASIZE,0)) == -1) { perror("recv"); exit(1); } printf("received a connection: %s\n",buf); //服务器端的发送和接收套接字必须都是客户端的---即accept函数的返回值 if ( sendbytes = send(client_fd,"server-I receive",17,0) == -1){ perror("send"); exit(1); } close(client_fd); }
两个重要函数:
1.accept()函数
int accept(int sockfd,struct
sockaddr *addr,socklen_t *addrlen);
sockfd,
利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连接;
addr<
4000
/span>, 指向struct
sockaddr的指针,该结构用通讯层服务器对等套接字的地址(一般为客户端程序的地址)填写,返回地址addr的确切格式由套接字的地址类别(比如TCP或UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,应该置为NULL;
备注:addr是个指向局部数据结构sockaddr_in的指针,这就是要求接入的套接字(地址和指针)。
addrlen,
一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值,函数返回时包含对等地址(一般为服务器地址)的实际数值;
accept()用来接受参数s 的socket 连线. 参数s 的socket 必需先经bind()、listen()函数处理过,
当有连线进来时accept()会返回一个新的socket 处理代码, 往后的数据传送与读取就是经由新的socket处理, 这个新的socket与原来的socket不一样,原来参数s
的socket 能继续使用accept()来接受新的连线要求. 连线成功时, 参数addr 所指的结构会被系统填入远程主机的地址数据(客户端所传来的服务器端的具体地址), 参数addrlen 为scokaddr 的结构长度.
再次调用accept()可以接受下一个客户端的连接请求,并再次返回一个新的套接字(与socket()返回的套接字、之前accept()返回的套接字都不同的新的套接字)。这个新的套接字用于与这次接受的客户端之间的通信。
2.connect()函数
connect()用来将参数sockfd
的socket 连至参数serv_addr 指定的网络地址. 结构sockaddr请参考bind(). 参数addrlen 为sockaddr 的结构长度.
connect函数完成主动连接的过程,功能是完成一个有连接协议的连接过程,对于TCP来说就是那个三路握手过程.
int connect(int sockfd, const struct sockaddr* server_addr,socklen_t addrlen)
返回:0──成功, -1──失败。
参数sockfd
指定数据发送的套接字,解决从哪里发送的问题。内核需要维护大量IO通道,所以用户必需通过这个参数告诉内核从哪个IO通道,此处就是从哪个socket接口中发送数据。sockfd是先前socket返回的值。
参数server_addr
指定数据发送的目的地,也就是服务器端的地址。这里服务器是针对connect说的,因为connect是主动连接的一方调用的,所以相应的要存在一个被连接的一方,被动连接的一方需要调用listen以接受connect的连接请求,如此被动连接的一方就是服务器了。
参数addrlen
指定server_addr结构体的长度。我们知道系统中存在大量的地址结构,但socket接口只是通过一个统一的结构来指定参数类型,所以需要指定一个长度,以使内核在进行参数复制的时候有个有个界限。
相关文章推荐
- Linux网络编程--TCP网络编程基础(简单的server/client模型)
- 使用Java网络编程创建基于TCP协议的Server和Client
- Linux网络编程中tcp_server和tcp_client函数的封装
- linux(or Windows) 异步网络编程 simple client-server-select 应用
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- Java 在Client/Server 网络中的应用-Java基础-Java-编程开发
- linux下的tcp的server和client编程
- 一个linux UDP网络通讯的例子源代码(server、client方式
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- 一个简单的Linux下Client/Server应答例子
- 一个简单的Linux下Client/Server应答例子
- 一个简单的Linux下Client/Server应答例子
- 一个linux UDP网络通讯的例子源代码(server、client方式)
- 简单网络编程--TCP SERVER 端
- Linux 网络编程基础 客户端/服务器的简单实现
- 一个简单的Linux下Client/Server应答例子
- 3个学习Socket编程的简单例子:TCP Server/Client, Select
- 一个linux UDP网络通讯的例子源代码(server、client方式)
- Linux下使用C做简单的网络编程
- linux下简单网络编程