1. Linux网络编程与普通程序区别
网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端.
1.1 客户端
主动与与外面的程序通信的程序。
例如使用ftp工具在Linux与Windows传文件时,ftp程序就是一个客户端程序,会去主动通信来获取文件。
1.2 服务器
被动的等待外面的程序来与自己通信的程序。
例如在ftp工具使用过程中,与ftp进行通信的程序就是服务器,可以从服务器获取文件。
2. Linux常用网络调试命令
netstat
令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项.
我们常用的选项是-na 用来显示详细的网络状态。
telnet
telnet是一个用来登录远程的程序,但是我们完全可以用这个程序来调试我们的服务端程序的.
比如我们的服务器程序在监听8888端口,我们可以用
telnet localhost 8888
来查看服务端的状况.
ping
ping 程序用来判断网络的状态是否正常,最经常的一个用法是
ping 192.168.1.1
表示我们想查看到192.168.1.1的硬件连接是否正常
3. TCP/UDP协议简单介绍
3.1 TCP协议
TCP(Transfer Control Protocol)传输控制协议是一种面向连接的协议, 在收发数据之前必须和对方建立可靠的连接(三次握手)。
当我们的网络程序使用这个协议的时候, 网络可以保证我们的客户端和服务端的连接是可靠的,安全的.
当客户端收到服务器的数据时,服务器会向客户端发送一个信号表示收到了数据,否则数据就会重新发送。
一般传输文件,命令等数据使用TCP来传输,保证数据的可靠性。
3.2 UDP协议
UDP(User Datagram Protocol)用户数据报协议是一种非面向连接的协议,它不与对方建立连接,而是直接就把数据包发送过去!
这种协议并不能保证我们的网络程序的连接是可靠的。
一般视频传输时使用UDP来进行传输,保证数据的实时性。
4. Linux下Socket编程
参考文章: [Linux网络编程入门](http://blog.csdn.net/jenshy/archive/2006/04/18/667944.aspx)
4.1 TCP传输
服务器端: 客户端(主动发起连接):
/* 相当于读写文件时的open函数,会返回一个sd描述符*/
a. sd = socket(); ---------------------------------------------- a. sd = socket();
/* 服务器一直在被动的响应请求,同时也在一直监测某个端口。
* bind函数可以将自己的ip,端口与sd绑定,
* 以后会监测ip与端口查看是否有数据传输过来
*/
b. bind(自己的ip,端口);
/* 启动监测数据 */
c. listen();
/* 客户端会发起连接,接受连接 */ /* 发送连接 */
d. accept(); ----------------------------------------------- b.connect(目的);
/* 发送数据 */
e. send(); ----------------------------------------------- c.recv();
/* 接受数据 */
f. recv(); ----------------------------------------------- d.send();
代码示例(服务器端接受多个客户端发送的数据,每个客户端进行连接时都会服务器端都会创建一个子进程来打印出数据)
TCP通信服务器端程序 server.c :`
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/* tcp协议服务器程序 */
int main(int argc, char **argv)
{
int ret;
int client_num = -1;
int server_sd;
int client_sd;
struct sockaddr_in SocketServerAddr;
struct sockaddr_in SocketClientAddr;
socklen_t adder_len;
int recv_len;
char buf[1000];
/* 1. socket
* AF_INET ---> ipv4协议
* SOCK_STREAM--> tcp协议
*/
server_sd = socket(AF_INET, SOCK_STREAM, 0);
if (server_sd < 0)
{
printf("socket error\n\r");
}
/* 2.bind
* sd----------------->socket_id
* SocketServerAddr--->addr_and_port
*/
SocketServerAddr.sin_family = AF_INET; /* 与ipv4对应 */
SocketServerAddr.sin_port = htons(8888); /* 监听端口,host to short */
SocketServerAddr.sin_addr.s_addr = INADDR_ANY; /* 监听地址为本机的所有ip */
memset(SocketServerAddr.sin_zero, 0, 8);
ret = bind(server_sd, (struct sockaddr *)&SocketServerAddr,sizeof (struct sockaddr));
if (ret == -1)
{
printf("bind error\n\r");
return -1;
}
/* 3.listen
* backlog:设置请求排队的最大长度.当有多个客户端程序和服务端相连时,
* 使用这个表示可以介绍的排队长度.
*/
ret = listen(server_sd, 10);
if (-1 == ret )
{
printf("listen error\n\r");
return -1;
}
/* 4.accept */
while (1)
{
adder_len = sizeof (struct sockaddr);
client_sd = accept(server_sd, (struct sockaddr *)&SocketClientAddr,&adder_len );
if (client_sd == -1)
{
printf("accept error\n\r");
return -1;
}
else
{
client_num++;
/* network to ascii */
printf("sucess connect client %s\n", inet_ntoa(SocketClientAddr.sin_addr));
}
/* 每当主进程接受到一个客户端连接时创建一个子进程,
子进程接收客户端数据并打印 */
if (!fork())
{
while (1)
{
/* 子进程一直读取数据 */
recv_len = recv(client_sd, buf, 1000, 0);
if (recv_len <= 0)
{
close(client_sd);
return -1;
}
buf[recv_len] = '\0';
printf("recv client %d : %s\n\r", client_num, buf);
}
}
}
close(server_sd);
return 0;
}
TCP通信客户端程序client.c:
/* client.c */
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int ret;
int client_sd;
int send_len;
char send_buf[1000];
char *tmp;
struct sockaddr_in SocketClientAddr;
if (argc != 2)
{
printf("Usage: \n");
printf("%s <server_ip>", argv[0]);
return -1;
}
/* 1. socket
* AF_INET ---> ipv4协议
* SOCK_STREAM--> tcp协议
*/
client_sd = socket(AF_INET, SOCK_STREAM, 0);
if (client_sd < 0)
{
printf("socket error\n\r");
return -1;
}
SocketClientAddr.sin_family = AF_INET; /* 与ipv4对应 */
SocketClientAddr.sin_port = htons(8888); /* 监听端口,host to short */
inet_aton(argv[1],&SocketClientAddr.sin_addr); /* 监听地址为本机的所有ip */
memset(SocketClientAddr.sin_zero, 0, 8);
ret = connect(client_sd, (struct sockaddr *)&SocketClientAddr,sizeof(struct sockaddr));
if (-1 == ret )
{
printf("connect error\n\r");
return -1;
}
while (1)
{
if (fgets(send_buf, 1000, stdin))
{
send_len = send(client_sd, send_buf, strlen(send_buf), 0);
if (send_len <= 0)
{
printf("send error\n\r");
close(client_sd);
return -1;
}
}
}
close(client_sd);
return 0;
}
4.2 UDP传输
服务器端: 客户端(主动发起连接):
/* 相当于读写文件时的open函数,会返回一个sd描述符*/
a. sd = socket(); -------------------------------------------------- a. sd = socket();
/* 不会真正去连接,只是为了包含目的信息 */
/* 可以不用连接,但是在发生数据时要使用sento函数发送,参数包含目的地址等信息 */
/* 服务器一直在被动的响应请求,同时也在一直监测某个端口。 b. connect()
* bind函数可以将自己的ip,端口与sd绑定,
* 以后会监测ip与端口查看是否有数据传输过来
*/
b. bind(自己的ip,端口);
/* 无需listen,accept */
/* 发送数据 */
e. sendto(); ----------------------------------------------- c.recvfrom();
/* 接受数据 */
f. recvfrom(); ----------------------------------------------- d.sendto();
UDP通信服务器程序 : /* server.c */
/* server.c */
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int ret;
int addr_len;
int recv_len;
int server_sd;
struct sockaddr_in SocketServerAddr;
struct sockaddr_in SocketClientAddr;
char buf[1000];
server_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (server_sd < 0)
{
printf("socket error\n");
return -1;
}
SocketServerAddr.sin_family = AF_INET;
SocketServerAddr.sin_port = htons(8888);
SocketServerAddr.sin_addr.s_addr = INADDR_ANY;
memset(SocketServerAddr.sin_zero, 0, 8);
ret = bind(server_sd, (struct sockaddr *)&SocketServerAddr,sizeof (struct sockaddr));
if (-1 == ret)
{
printf("bind error\n");
return -1;
}
while (1)
{
addr_len = sizeof (struct sockaddr);
recv_len = recvfrom(server_sd, buf, 999, 0, (struct sockaddr *)&SocketClientAddr, &addr_len);
if (recv_len > 0)
{
buf[recv_len] = '\0';
printf("Get msg from %s : %s\n", inet_ntoa(SocketClientAddr.sin_addr), buf);
}
else
{
close(server_sd);
return -1;
}
}
return 0;
}
UDP通信客户端程序:`/* client.c */
/* client.c */
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
//#define CONNECT
int main(int argc, char **argv)
{
int ret;
int client_sd;
int send_len;
int addr_len;
struct sockaddr_in SocketClientAddr;
char buf[1000];
if (argc != 2)
{
printf("Usage: \n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
client_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (client_sd < 0)
{
printf("socket error\n");
return -1;
}
SocketClientAddr.sin_family = AF_INET;
SocketClientAddr.sin_port = htons(8888);
if (inet_aton(argv[1], &SocketClientAddr.sin_addr) == 0)
{
printf("invalid address\n");
return -1;
}
memset(SocketClientAddr.sin_zero, 0, 8);
#ifdef CONNECT
ret = connect(client_sd, (struct sockaddr *)&SocketClientAddr, sizeof (struct sockaddr));
if (-1 == ret)
{
printf("connect error\n");
return -1;
}
#endif
while (1)
{
if (fgets(buf, 1000, stdin))
{
#ifdef CONNECT
send_len = send(client_sd, buf, strlen(buf), 0);
if (send_len <= 0)
{
printf("send error\n");
return -1;
}
#else
send_len = sendto(client_sd, buf, strlen(buf), 0, (const struct sockaddr *)&SocketClientAddr, sizeof (struct sockaddr));
if (send_len <= 0)
{
printf("send error\n");
return -1;
}
#endif
}
}
return 0;
}