Linux学习之socket编程(二)
Linux学习之socket编程(二)
1.C/S模型——UDP

UDP处理模型
由于UDP不需要维护连接,程序逻辑简单了很多,但是UDP协议是不可靠的,实际上有很多保证通讯可靠性的机制需要在应用层实现。多保证通讯可靠性的机制需要在应用层实现。编译运行server,在两个终端里各开一个client与server交互,看看server是否具有并发服务的能力。用Ctrl+C关闭server,然后再运行server,看此时client还能否和server联系上。和前面TCP程序的运行结果相比较,体会无连接的含义。

/* server.c */ #include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 8000 int main(void)
{
struct sockaddr_in servaddr, cliaddr;//用于IPv4的地址
socklen_t cliaddr_len;
int sockfd;//文件描述符
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];//16 Bytes
int i, n;
/*构造用于UDP通信的套接字*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);// bzero(&servaddr, sizeof(servaddr));//将地址清零
//设置地址
servaddr.sin_family = AF_INET;/*IPv4*/
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//网络字节数,本地任意IP
servaddr.sin_port = htons(SERV_PORT);
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); printf("Accepting connections ...\n");
while (1) {
cliaddr_len = sizeof(cliaddr); n = recvfrom(sockfd, buf, MAXLINE, 0, (struct sockaddr *)&cliaddr, &cliaddr_len); if (n == -1)
perr_exit("recvfrom error");
printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port)); for (i = 0; i < n; i++)
buf[i] = toupper(buf[i]);//小写转大写 //发送数据
n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr)); if (n == -1)
perr_exit("sendto error");
}
}


/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
int sockfd, n;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
socklen_t servaddr_len; sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT); while(fgets(buf, MAXLINE, stdin) != NULL) { n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (n == -1)
perr_exit ("sendto error"); n = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0); if (n == -1)
perr_exit("recvfrom error");
write(STDOUT_FILENO, buf, n);//写到屏幕上
}
close(sockfd);
return 0;
}

2.出错处理封装函数 上面的例子不仅功能简单,而且简单到几乎没有什么错误处理,我们知道,系统调用不能保证每次都成功,必须进行出错处理,这样一方面可以保证程序逻辑正常,另一方面可以迅速得到故障信息。为使错误处理的代码不影响主程序的可读性,我们把与socket相关的一些系统函数加上错误处理代码包装成新的函数,做成一个模块wrap.c:

#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
void perr_exit(const char *s)
{
perror(s);
exit(1);
} int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
int n;
again:
if ( (n = accept(fd, sa, salenptr)) < 0) {
if ((errno == ECONNABORTED) || (errno == EINTR))
goto again;
else
perr_exit("accept error");
}
return n;
} void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
perr_exit("bind error");
} void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (connect(fd, sa, salen) < 0)
perr_exit("connect error");
} void Listen(int fd, int backlog)
{
if (listen(fd, backlog) < 0)
perr_exit("listen error");
} int Socket(int family, int type, int protocol)
{
int n;
if ( (n = socket(family, type, protocol)) < 0)
perr_exit("socket error");
return n;
} ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
again:
if ( (n = read(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
} ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
ssize_t n;
again:
if ( (n = write(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
} void Close(int fd)
{
if (close(fd) == -1)
perr_exit("close error");
} ssize_t Readn(int fd, void *vptr, size_t n)//指定读够n个字节返回
{
size_t nleft;
ssize_t nread;
char *ptr; ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0;
else
return -1;
} else if (nread == 0)
break; nleft -= nread;
ptr += nread; }
return n - nleft;
} ssize_t Writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr; ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
} static ssize_t my_read(int fd, char *ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf[100]; if (read_cnt <= 0) {
again:
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
if (errno == EINTR)
goto again;
return -1;
}
else if (read_cnt == 0)
return 0;
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;
return 1;
} ssize_t Readline(int fd, void *vptr, size_t maxlen)//一次读一行
{
ssize_t n, rc;
char c, *ptr; ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ( (rc = my_read(fd, &c)) == 1) {
*ptr++ = c;
if (c == '\n')
break;
} else if (rc == 0) {
*ptr = 0;
return n - 1;
} else
return -1;
}
*ptr = 0;
return n;
}


#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
void perr_exit(const char *s)
{
perror(s);
exit(1);
} int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
int n;
again:
if ( (n = accept(fd, sa, salenptr)) < 0) {
if ((errno == ECONNABORTED) || (errno == EINTR))
goto again;
else
perr_exit("accept error");
}
return n;
} void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
perr_exit("bind error");
} void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (connect(fd, sa, salen) < 0)
perr_exit("connect error");
} void Listen(int fd, int backlog)
{
if (listen(fd, backlog) < 0)
perr_exit("listen error");
} int Socket(int family, int type, int protocol)
{
int n;
if ( (n = socket(family, type, protocol)) < 0)
perr_exit("socket error");
return n;
} ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
again:
if ( (n = read(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
} ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
ssize_t n;
again:
if ( (n = write(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
} void Close(int fd)
{
if (close(fd) == -1)
perr_exit("close error");
} ssize_t Readn(int fd, void *vptr, size_t n)//指定读够n个字节返回
{
size_t nleft;
ssize_t nread;
char *ptr; ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0;
else
return -1;
} else if (nread == 0)
break; nleft -= nread;
ptr += nread; }
return n - nleft;
} ssize_t Writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr; ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
} static ssize_t my_read(int fd, char *ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf[100]; if (read_cnt <= 0) {
again:
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
if (errno == EINTR)
goto again;
return -1;
}
else if (read_cnt == 0)
return 0;
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;
return 1;
} ssize_t Readline(int fd, void *vptr, size_t maxlen)//一次读一行
{
ssize_t n, rc;
char c, *ptr; ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ( (rc = my_read(fd, &c)) == 1) {
*ptr++ = c;
if (c == '\n')
break;
} else if (rc == 0) {
*ptr = 0;
return n - 1;
} else
return -1;
}
*ptr = 0;
return n;
}


/* wrap.h */
#ifndef __WRAP_H_
#define __WRAP_H_ void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
void Bind(int fd, const struct sockaddr *sa, socklen_t salen);
void Connect(int fd, const struct sockaddr *sa, socklen_t salen);
void Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
void Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
static ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen); #endif


/* wrap.h */
#ifndef __WRAP_H_
#define __WRAP_H_ void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
void Bind(int fd, const struct sockaddr *sa, socklen_t salen);
void Connect(int fd, const struct sockaddr *sa, socklen_t salen);
void Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
void Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
static ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen); #endif

Linux学习之socket编程(二)的更多相关文章
- Linux学习之socket编程(一)
socket编程 socket的概念: 在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址+端口号”就称为socket. 在TCP协议中,建立连接的两个进 ...
- Linux学习总结(十二)—— CentOS用户管理:创建用户、修改用户、修改密码、密码有效期、禁用账户、解锁账户、删除用户、查看所有用户信息
文章首发于Linux学习总结(十二)-- CentOS用户管理,请尊重原创保留原文链接. 创建用户 useradd -g webadmin -d /home/zhangsan zhangsan pas ...
- linux网络编程之socket编程(二)
今天继续对socket编程进行研究,这里会真正开如用socket写一个小例子,进入正题: TCP客户/服务器模型: 关于这个模型的流程这里就不多说了,比较容易理解,下面则利用这种模型来编写一个实际 ...
- Linux下网络socket编程——实现服务器(select)与多个客户端通信
一.关于socket通信 服务器端工作流程: 调用 socket() 函数创建套接字 用 bind() 函数将创建的套接字与服务端IP地址绑定 调用listen()函数监听socket() 函数创建的 ...
- Linux下Golang Socket编程原理分析与代码实现
在POSIX标准推出后,socket在各大主流OS平台上都得到了很好的支持.而Golang是自带Runtime的跨平台编程语言,Go中提供给开发者的Socket API是建立在操作系统原生Socket ...
- Linux 应用开发----socket编程笔记
Linux socket编程 套接字定义描述 套接字的域 AF_INET ====>IPv4 AF_INET6 ====>IPv6 AF_UNIX ====>unix 域 AF_UP ...
- Linux学习之日志管理(二十一)
Linux学习之日志管理 目录 日志管理 日志服务 rsyslogd的新特点 启动日志服务 常见日志的作用 日志文件的一般格式 rsyslogd日志服务 /etc/rsyslog.conf配置文件 服 ...
- Linux学习 : Socket 网络编程入门
一.socket()函数 int socket(int domain, int type, int protocol); domain:即协议域,又称为协议族(family).常用的协议族有,AF_I ...
- 网络编程学习笔记:linux下的socket编程
socket是进程通信的一种方式,通过调用一些API可以实现进程间通信,建立连接以及收发信息的过程如下图所示: 这些函数的用法如下: 1.int socket(int protocolFamily, ...
随机推荐
- Python 批量处理特定格式文件
#批量对文件夹下的'.mat'进行处理 def file_name(file_dir,suff): L=[] for root, dirs, files in os.walk(file_dir): f ...
- python继承 super()
写这篇博文,始于以下问题的探究: #coding:utf-8 class A(object): def __init__(self): print 'enter A' print 'leave A' ...
- js验证输入框
项目开发中,都会有对表单form中的input输入框进行一些限制验证 如: <!DOCTYPE html><html lang="en"> <head ...
- hadoop-17-hive数据库元数据查看
hadoop-17-hive数据库元数据查看 存在本地的mysql中: user001用户中 : > mysql -uhive -phive mysql> use hive; mysql& ...
- HDU 3016 Man Down(线段树)
HDU 3016 Man Down 题目链接 题意:是男人就下100层的游戏的简单版,每次仅仅能从两端下落.求落地最大血量 思路:利用线段树能够处理出每一个线段能来自哪几个线段.然后就是dag最长路了 ...
- eclipse软件快捷键的使用
[Ct rl+T] 搜索当前接口的实现类 1. [ALT +/] 此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时,多体验一下[ ...
- Light OJ 1080 - Binary Simulation
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1080 1080 - Binary Simulation PDF (Englis ...
- c++命名规范与代码风格
http://blog.sina.com.cn/s/blog_a3a8d0b1010100uw.html http://www.cnblogs.com/len3d/archive/2008/02/01 ...
- rest_framework 视图
视图: a.过去 class PagerView(View): pass b.现在 class Pager1View(APIView): pass c.rest_framework 基本没用 from ...
- rest_framework 节流功能(访问频率)
访问记录 = { 身份证号: [ :: ,::, ::] } #:: ,::,:: ,::, #:: #[::, ::, ::] #访问记录 = { 用户IP: [...] } import time ...