Linux c socket编程:简单的客户端(client)和服务端(server)实现
Linux系统是通过提供套接字(socket)来进行网络编程的。网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符。socket也有一个类似于打
开文件的函数:socket(),调用socket(),该函数返回一个整型的socket的描述符,随后的连接建立、数据传输等操作也都是通过该socket实现。
1)socket函数
函数原型:
1
|
int
socket(
int
domain,
int
type,
int
protocol);
|
功能说明:
调用成功,返回socket文件描述符;失败,返回-1,并设置errno
参数说明:
domain指明所使用的协议族,通常为PF_INET,表示TCP/IP协议;
type参数指定socket的类型,基本上有三种:数据流套接字、数据报套接字、原始套接字
两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。socket数据结构中包含这五种信息。
2)bind函数
函数原型:
1
|
int
bind(
int
sock_fd,
struct
sockaddr_in *my_addr,
int
addrlen);
|
功能说明:
将套接字和指定的端口相连。成功返回0,否则,返回-1,并置errno.
参数说明:
sock_fd是调用socket函数返回值,
my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
struct sockaddr_in结构类型是用来保存socket信息的:
struct sockaddr_in {
struct in_addr sin_addr;
};
addrlen为sockaddr的长度。
3)connect函数
函数原型:
1
|
int
connect(
int
sock_fd,
struct
sockaddr *serv_addr,
int
addrlen);
|
功能说明:
客户端发送服务请求。成功返回0,否则返回-1,并置errno。
参数说明:
sock_fd 是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是结构sockaddr_in的长度。
4)listen函数
函数原型:
1
|
int
listen(
int
sock_fd,
int
backlog);
|
功能说明:
等待指定的端口的出现客户端连接。调用成功返回0,否则,返回-1,并置errno.
参数说明:
sock_fd 是socket()函数返回值;
5)accecpt函数
函数原型:
1
|
int
accept(
int
sock_fd,
struct
sockadd_in* addr,
int
addrlen);
|
功能说明:
用于接受客户端的服务请求,成功返回新的套接字描述符,失败返回-1,并置errno。
参数说明:
sock_fd是被监听的socket描述符,
addr通常是一个指向sockaddr_in变量的指针,
addrlen是结构sockaddr_in的长度。
6)write函数
函数原型:
1
|
ssize_t write(
int
fd,
const
void
*buf,
size_t
nbytes)
|
功能说明:
write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量.
在网络程序中,当我们向套接字文件描述符写时有俩种可能:
(1)write的返回值大于0,表示写了部分或者是全部的数据.
(2)返回的值小于0,此时出现了错误.需要根据错误类型来处理.
如果错误为EPIPE表示网络连接出现了问题.
7)read函数
函数原型:
1
|
ssize_t read(
int
fd,
void
*buf,
size_t
nbyte)
|
函数说明:
read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误.
如果错误为EINTR说明读是由中断引起的,
如果错误是ECONNREST表示网络连接出了问题.
8)close函数
函数原型:
1
|
int
close(sock_fd);
|
说明:
当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:
函数运行成功返回0,否则返回-1
(1) 网络字节顺序
每一台机器内部对变量的字节存储顺序不同,而网络传输的数据是一定要统一顺序的。所以对内部字节表示顺序与网络字节顺序不同的机器,一定要对数据进行转换,从程序的可移植性要求来讲,就算本机的内部字节表示顺序与网络字节顺序相同也应该在传输数据以前先调用数据转换函数,以便程序移植到其它机器上后能正确执行。真正转换还是不转换是由系统函数自己来决定的。
(2) 有关的转换函数
1
2
3
4
5
6
7
8
|
unsigned
short
int
htons(unsigned
short
int
hostshort):
//主机字节顺序转换成网络字节顺序,对无符号短型进行操作4bytes
unsigned
long
int
htonl(unsigned
long
int
hostlong):
//主机字节顺序转换成网络字节顺序,对无符号长型进行操作8bytes
unsigned
short
int
ntohs(unsigned
short
int
netshort):
//网络字节顺序转换成主机字节顺序,对无符号短型进行操作4bytes
unsigned
long
int
ntohl(unsigned
long
int
netlong):
//网络字节顺序转换成主机字节顺序,对无符号长型进行操作8bytes
|
注:以上函数原型定义在netinet/in.h里
2)IP地址转换
有三个函数将数字点形式表示的字符串IP地址与32位网络字节顺序的二进制形式的IP地址进行转换
(1) unsigned long int inet_addr(const char * cp):该函数把一个用数字和点表示的IP地址的字符串转换成一个无符号长整型,如:
1
2
|
struct
sockaddr_in ina;
ina.sin_addr.s_addr=inet_addr(
"222.216.117.11"
);
|
该函数成功时:返回转换结果;失败时返回常量INADDR_NONE,该常量=-1,二进制的无符号整数-1相当于255.255.255.255,这是一个广播地址,所以在程序中调用iner_addr()时,一定要人为地对调用失败进行处理。由于该函数不能处理广播地址,所以在程序中应该使用函数inet_aton()。
(2)int inet_aton(const char * cp,struct in_addr * inp):此函数将字符串形式的IP地址转换成二进制形式的IP地址;成功时返回1,否则返回0,转换后的IP地址存储在参数inp中。
(3) char * inet_ntoa(struct in-addr in):将32位二进制形式的ip地址转换为数字点形式的ip地址,结果在函数返回值中返回,返回的是一个指向字符串的指针。
3)字节处理函数
Socket地址是多字节数据,不是以空字符结尾的,这和C语言中的字符串是不同的。Linux提供了两组函数来处理多字节数据,一组以b(byte)开头,是和BSD系统兼容的函数,另一组以mem(内存)开头,是ANSI C提供的函数。
以b开头的函数有:
(1) void bzero(void * s,int n):将参数s指定的内存的前n个字节设置为0,通常它用来将套接字地址清0。
(2) void bcopy(const void * src,void * dest,int n):从参数src指定的内存区域拷贝指定数目的字节内容到参数dest指定的内存区域。
3 简单的客户端(client)和服务端(server)实现源码
1) 客户端源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
// gcc -g -o simple_client simple_client.c
int
main(
int
argc,
char
*argv[])
{
char
ip[20]={
"192.168.10.23"
};
int
port=10000;
int
server_fd;
struct
sockaddr_in server_listen_addr;
bzero(&server_listen_addr,
sizeof
(server_listen_addr));
server_listen_addr.sin_family=AF_INET;
server_listen_addr.sin_port=htons(port);
inet_pton(AF_INET,
"192.168.10.23"
,(
void
*)&server_listen_addr.sin_addr);
// inet_aton(ip,&server_listen_addr.sin_addr);
// bzero(&(server_listen_addr.sin_zero),8);
server_fd=socket(AF_INET,SOCK_STREAM,0);
int
ret=connect(server_fd,(
const
struct
sockaddr *)&server_listen_addr,
sizeof
(
struct
sockaddr));
printf
(
"server_fd=[%d] ret=[%d]n"
,server_fd,ret);
if
(ret<0)
{
perror
(
"error: socket connect!"
);
exit
(1);
}
char
data[20]={
"good luck!n"
};
int
num=send(server_fd,(
void
*)data,
strlen
(data),0);
printf
(
"send bytes[%d][%s]n"
,num,data);
close(server_fd);
return
1;
}
|
2)服务端源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
//gcc -g -o simple_server simple_server.c
int
main(
int
argc,
char
*argv[])
{
int
port=10000;
int
server_listen_fd;
int
server_accept_fd;
struct
sockaddr_in server_listen_addr;
struct
sockaddr_in server_accept_addr;
bzero(&server_listen_addr,
sizeof
(server_listen_addr));
bzero(&server_accept_addr,
sizeof
(server_accept_addr));
server_listen_addr.sin_family=AF_INET;
server_listen_addr.sin_addr.s_addr=INADDR_ANY;
server_listen_addr.sin_port=htons(port);
server_listen_fd=socket(AF_INET,SOCK_STREAM,0);
if
(-1==server_listen_fd)
{
perror
(
"fail to create socket!"
);
exit
(1);
}
if
(bind(server_listen_fd,(
struct
sockaddr*)&server_listen_addr,
sizeof
(server_listen_addr))==-1)
{
perror
(
"can't to bind"
);
exit
(1);
}
if
(listen(server_listen_fd,10)==-1)
{
perror
(
"can't to bind"
);
exit
(1);
}
while
(1)
{
int
size=
sizeof
(server_accept_addr);
printf
(
"server socket begin accept:n"
);
server_accept_fd=accept(server_listen_fd,(
struct
sockaddr*)&server_accept_addr,&size);
printf
(
"accept con_fd=%dn"
,con_fd);
if
(server_accept_fd<0)
{
perror
(
"error:socket accept!exited!n"
);
exit
(1);
}
int
num=0;
char
data[200]={0};
int
ret=read(server_accept_fd,(
void
*)data,199);
close(server_accept_fd);
printf
(
"DATA:[%s]n"
,data);
}
return
1;
}
|
您可能感兴趣的文章:
在Linux下开发手机客户端或Pc客户端交互的服务器,需要学哪些知识?
linux端是服务器,客户端连接后,有时并不知道客户端断开,怎么侦测?
linux 能ping通客户端ip,但ping不通客户端的域名。
Linux网络编程(怎样实现两个客户端之间的通信)
Linux的BBS客户端 QTerm
Linux的博客客户端 Drivel
Linux 代理 一个客户端来就创建一个连接
linux客户端如何配置网络?
linux socket多客户端程序
linux下用kerberos客户端加入windows域的问题
求助:Linux下ftp客户端代码编写
linux怎样装那个锐杰认证客户端
Linux系统做服务器,客户端可使用windows系列的系统吗
Linux下默认的邮件客户端是什么
linux作为客户端,跟windows通信,如何保持一直在线?
linux中监听客户端访问tomcat的命令
Linux的Twitter客户端 Twitux
Linux邮件客户端 Evolution
linux下的写的tcp客户端,connect到windows的服务器超时
Linux下c/c++ boost安装及并发编程库mpi介绍
都说《UNIX环境高级编程》好,对于学linux编程好不好?《Linux下的c编程》《嵌入式系统C编程》那个更适合初学者?各是那个出版社的?(
我想学Linux编程,请大家推荐几本学习Linux下C/C++编程的书
学Linux编程前要学Unix吗?哪里有学Linux编程的好书下载?
我想学习linux桌面编程,那么有没有必要学习linux的内核以及内核的相关编程呢?
linux下编程跟平时的编程有什么区别吗?
unix编程与linux编程有什么区别?
Linux下的编程指的就是Shell编程吗?
帮我介绍基本linux下编程的书,《Linux上的C编程》这本书怎么样?还有别的书吗?
Linux下使用openssl api编程socket编程,为什么要编译啊?
请教linux下的编程的选择:我听说有gtk+gnome的编程,也有kde里的 什么编程,到底应该选择哪个呢?好象一个是技术好一点,一个是市场占有
- 本站(WWW.169IT.COM)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.169IT.COM)站内文章除注明原创外,均为转载,整理或搜集自网络.欢迎任何形式的转载,转载请注明出处.
转载请注明:文章转载自:[169IT-IT技术资讯]
本文标题:Linux c socket编程:简单的客户端(client)和服务端(server)实现